配置Elasticsearch集群存算分离
随着数据量的快速增长,传统单一存储架构面临性能与成本的双重挑战。CSS服务的Elasticsearch集群通过存算分离方案,将热数据(频繁访问数据)与冷数据(历史归档数据)分离存储,既能保障实时查询性能,又能大幅降低长期存储成本。该方案适用于日志分析、审计回溯等对冷数据检索性能要求不高的场景。
原理介绍

- 热数据:高频访问数据,存储在高速SSD磁盘,支持毫秒级检索。
- 冷数据:低频访问的历史归档数据,转储至对象存储服务OBS桶(用户不可见),采用标准存储类型。
- 热索引(open):支持数据写入和毫秒级检索。
- 冻结索引(freeze):将低频访问的索引数据转储至OBS,索引变为只读,检索速率降低到秒/分级别。
- 删除索引:冻结索引支持定期删除,释放存储资源。
计费影响
当启用存算分离冻结索引时,系统会将指定索引转储到OBS服务中,存储类别为标准存储类型。该OBS桶对用户不可见,无法通过OBS控制台进行查看或管理。需要注意的是,存储在OBS桶中的索引数据将产生额外费用,该费用仅支持按需计费模式,根据实际使用的标准存储容量进行计算。具体费用估算请参见云搜服务价格计算器。
约束限制
- Elasticsearch集群仅7.6.2和7.10.2版本支持存算分离功能。
- 在执行冻结索引前,系统会将待冻结的索引配置为只读状态,即便在索引数据转储到OBS后,索引也是只读状态,不支持写入数据。
- 在冻结索引过程中,查询请求不受影响。在冻结完成后,会将索引先Close再Open,在这段时间内,索引不可查询,集群可能短暂出现Red状态,索引Open结束后集群恢复正常。
- 索引冻结成功后,索引会被转储到OBS桶中,此时本地磁盘中的索引数据会被删除。当查询被冻结的索引时,时延会增加,在聚合时,由于查询复杂、数据读取多,时延变长会更明显。
- 已转储到OBS中的索引不支持解冻,即不可回退为可写的索引。
- 在配置了读写分离的集群中,从集群无法对由主集群同步过来的索引数据设置存算分离。
- 冻结索引时,数据转储到OBS桶中会占用网络带宽,所以使用过程中要遵守OBS的“带宽”和“每秒请求数(QPS)”的使用限制,详细请参见OBS使用限制。当超过限制时,集群中涉及到OBS查询的性能都会下降,例如恢复分片的速度变慢、查询数据时变慢等。
登录Kibana
登录Kibana进入命令执行页面。Elasticsearch集群支持多种客户端访问,本文仅以CSS服务集成的Kibana为例介绍配置指导。
- 登录云搜索服务管理控制台。
- 在左侧导航栏,选择“集群管理 > Elasticsearch”。
- 在集群列表,选择目标集群,单击操作列的“Kibana”,登录Kibana。
- 在Kibana左侧导航栏选择“Dev Tools”,进入操作页面。
冻结索引
将热数据转储至OBS桶,降低SSD存储压力。索引变为只读状态。
- 冻结索引。
index_name是待冻结的索引名称。
返回示例:
{ "freeze_uuid": "pdsRgUtSTymVDWR_HoTGFw" }
freeze_uuid是冻结任务的ID,在提交冻结请求后会启动一个异步任务,请求返回任务ID,使用该ID可以查询冻结索引任务的进度。
- 查看冻结任务进度。
返回示例:
{ "stage" : "STARTED", "shards_stats" : { "INIT" : 0, "FAILURE" : 0, "DONE" : 0, "STARTED" : 1, "ABORTED" : 0 }, "indices" : { "data1" : [ { "uuid" : "7OS-G1-tRke2jHZPlckexg", "index" : { "name" : "data1", "index_id" : "4b5PHXJITLaS6AurImfQ9A", "shard" : 2 }, "start_ms" : 1611972010852, "end_ms" : -1, "total_time" : "10.5s", "total_time_in_millis" : 10505, "stage" : "STARTED", "failure" : null, "size" : { "total_bytes" : 3211446689, "finished_bytes" : 222491269, "percent" : "6.0%" }, "file" : { "total_files" : 271, "finished_files" : 12, "percent" : "4.0%" }, "rate_limit" : { "paused_times" : 1, "paused_nanos" : 946460970 } } ] } }
表1 返回参数说明 参数
描述
stage
冻结任务的当前状态。
取值范围:- INIT:刚启动或者正在初始化。
- FAILURE:失败。
- DONE:完成。
- STARTED:已启动。
- ABORTED:取消,预留字段。
shards_stats
冻结任务中,处在各个状态的shard个数。
indices
每个索引的状态详情,如表2所示。
表2 indices参数说明 参数
描述
uuid
冻结任务的ID。
index
索引信息和shard信息。
start_ms
任务开始时间。
end_ms
任务结束时间,如果没有结束则显示为-1。
total_time
任务已花费时间。
total_time_in_millis
任务已花费时间毫秒数。
stage
当前shard所处的状态。
failure
任务失败原因,如果没有失败则显示为null。
size.total_bytes
总共需要冻结的文件字节数。
size.finished_bytes
已经完成冻结的文件字节数。
size.percent
已经完成冻结的字节数百分比。
file.total_bytes
总共需要冻结的文件个数。
file.finished_bytes
已经完成冻结的文件个数。
file.percent
已经完成冻结的文件个数百分比。
rate_limit.paused_times
达到限速导致冻结暂停的次数。
rate_limit.paused_nanos
达到限速导致冻结暂停的时间纳秒数。
冻结完成的索引还会返回settings参数,如表3所示。
- 查询冻结索引列表。
执行如下命令,基于索引的冻结状态查询索引列表。
GET _cat/freeze_indices?stage={STAGE}
STAGE是待查询的索引冻结状态,取值范围如下:
- start:开始冻结但还未完成冻结。
- done:已经完成冻结。
- unfreeze:没有启动冻结任务。
- 空或者其他值:正在冻结中和已经冻结完成。
返回示例:
green open data2 0bNtxWDtRbOSkS4JYaUgMQ 3 0 5 0 7.9kb 7.9kb green open data3 oYMLvw31QnyasqUNuyP6RA 3 0 51 0 23.5kb 23.5kb
配置OBS中的缓存优化
冻结索引后,索引数据转储到OBS,为了尽可能地减少对OBS的访问请求,提升集群的查询性能,系统会缓存部分数据。第一次查询冷数据时,集群会直接访问OBS,获取到的数据会被缓存在集群内存中,后续查询时会先检查是否有缓存数据。CSS服务支持查询和重置存储在OBS桶中的冻结索引的缓存状态,以及修改缓存配置。
- 查询存储在OBS桶中冻结索引的缓存状态。
- 执行如下命令,查询所有节点中冻结索引的缓存信息。
GET _frozen_stats
- 执行如下命令,查询指定节点中冻结索引的缓存信息。
GET _frozen_stats/{node_id}
node_id是集群节点ID。
查询所有节点中冻结索引的缓存信息的返回示例:
{ "_nodes" : { "total" : 1, // 所有节点数量 "successful" : 1, // 成功的节点数量 "failed" : 0 // 失败的节点数量 }, "cluster_name" : "css-zzz1", // 集群名称 "nodes" : { "7uwKO38RRoaON37YsXhCYw" : { "name" : "css-zzz1-ess-esn-2-1", // 节点名称 "transport_address" : "10.0.0.247:9300", // 节点transport连接地址 "host" : "10.0.0.247", // 节点host "ip" : "10.0.0.247", // 节点IP "block_cache" : { "default" : { "type" : "memory", // cache类型,memory表示内存cache "block_cache_capacity" : 8192, // cache容量 "block_cache_blocksize" : 8192, // cache中单个block大小,单位为bytes,如此处表示8k "block_cache_size" : 12, // cache已被占用的大小 "block_cache_hit" : 14, // cache命中数 "block_cache_miss" : 0, // cache未命中数 "block_cache_eviction" : 0, // cache被逐出次数 "block_cache_store_fail" : 0 // 如果cache满了,可能导致新的cache存储失败,此处表示存储失败的次数 } }, "obs_stats" : { "list" : { "obs_list_count" : 17, // 调用OBS list接口的次数 "obs_list_ms" : 265, // 调用OBS list接口的总耗时 "obs_list_avg_ms" : 15 // 调用OBS list接口的平均耗时 }, "get_meta" : { "obs_get_meta_count" : 79, // 调用OBS 获取元数据接口的次数 "obs_get_meta_ms" : 183, // 调用OBS 获取元数据接口的总耗时 "obs_get_meta_avg_ms" : 2 // 调用OBS 获取元数据接口的平均耗时 }, "get_obj" : { "obs_get_obj_count" : 12, // 调用OBS getObject接口的次数 "obs_get_obj_ms" : 123, // 调用OBS getObject接口的总耗时 "obs_get_obj_avg_ms" : 10 // 调用OBS getObject接口的平均耗时 }, "put_obj" : { "obs_put_obj_count" : 12, // 调用OBS putObject接口的总次数 "obs_put_obj_ms" : 2451, // 调用OBS putObject接口的总耗时 "obs_put_obj_avg_ms" : 204 // 调用OBS putObject接口的平均耗时 }, "obs_op_total" : { "obs_op_total_ms" : 3022, // 调用OBS接口的总耗时 "obs_op_total_count" : 120, // 调用OBS接口的总次数 "obs_op_avg_ms" : 25 // 调用OBS接口的平均耗时 } }, "reader_cache" : { "hit_count" : 0, "miss_count" : 1, "load_success_count" : 1, "load_exception_count" : 0, "total_load_time" : 291194714, "eviction_count" : 0 } } } }
- 执行如下命令,查询所有节点中冻结索引的缓存信息。
- 重置存储在OBS桶中冻结索引的缓存状态。
POST _frozen_stats/reset
此命令主要用于调试性能问题,例如重置缓存状态后再次执行查询可以清晰看到本次查询的缓存命令情况。在业务运行阶段不需要执行此命令。
返回结果如下:
{ "_nodes" : { "total" : 1, "successful" : 1, "failed" : 0 }, "cluster_name" : "Es-0325-007_01", "nodes" : { "mqTdk2YRSPyOSXfesREFSg" : { "result" : "ok" } } }
- 修改存储在OBS桶中冻结索引的缓存配置。
集群访问不同的文件,访问的模式是不一样的,缓存系统支持多级缓存,会使用不同大小的block来缓存不同的文件,例如fdx和tip文件会使用大量的小block缓存,对fdt文件会使用较少的大block缓存。缓存配置支持基于业务情况进行修改,参数如表4所示。
表4 缓存配置参数说明 配置项
类型
描述
low_cost.obs.blockcache.names
Array
缓存系统支持的多级缓存名称列表。缓存系统支持多级缓存,分别用来缓存不同访问粒度的数据。
系统默认包含一个名为default的缓存。如果配置此参数,必须至少包含一个名为default的缓存,其他缓存名称可自定义。
默认值:default。
low_cost.obs.blockcache.<NAME>.type
ENUM
指定名为<NAME>的缓存使用的类型。
取值范围:
- memory:使用内存作为缓存存储,会占用系统内存资源。
- file:使用磁盘作为缓存存储,缓存容量受磁盘空间限制。建议使用超高IO型磁盘提升缓存性能。
默认值:memory
low_cost.obs.blockcache.<NAME>.blockshift
Integer
指定名为<NAME>的缓存中每个Block的大小(以字节为单位)。
计算方式为 2blockshift。例如,配置值为16,则Block大小为 216 字节,即65536字节或64KB。
单位:字节左移数。
默认值:13(对应8KB)
low_cost.obs.blockcache.<NAME>.bank.count
Integer
指定名为<NAME>的缓存的分区数量。每个分区是缓存的一个独立单元。
默认值:1
low_cost.obs.blockcache.<NAME>.number.blocks.perbank
Integer
指定名为<NAME>的缓存中,每个分区包含的Block数量。
默认值:8192
low_cost.obs.blockcache. <NAME>.exclude.file.types
Array
指定名为<NAME>的缓存,不缓存的文件后缀名列表。
如果一个文件的后缀既不在“exclude.file.types”列表中,也不在“<NAME>.file.types”列表中(如果配置了“<NAME>.file.types”),则该文件将使用default缓存策略。
low_cost.obs.blockcache. <NAME>.file.types
Array
指定名为<NAME>的缓存,缓存的文件后缀名列表。
如果一个文件的后缀既不在“exclude.file.types”列表中,也不在“<NAME>.file.types”列表中(如果配置了“<NAME>.file.types”),则该文件将使用default缓存策略。
index.frozen.obs.max_bytes_per_sec
String
配置冻结索引过程中向OBS上传文件的最大速率限制。
格式为 <数值><单位>。单位支持B (字节)、KB、MB、GB。
修改此配置后立即生效。
默认值:150MB
low_cost.obs.index.upload.threshold.use.multipart
String
分段上传阈值,配置冻结索引过程中,单个文件大小超过此阈值时,使用OBS的分段上传机制。
格式为 <数值><单位>。单位支持B (字节)、KB、MB、GB。
冻结过程中文件大小超过此配置会使用OBS的分段上传。
0或不配置可能表示禁用分段上传。
默认值:1GB
下面是一个常见的缓存配置示例,该配置使用两级缓存,名字分别为“default”和“large”。其中,“default”缓存使用大小为64K的block,一共有30*4096个block,“default”缓存用于缓存除fdt后缀的其他文件,“large”缓存使用大小为2M的block,一共有5*1000个block,“large”缓存用于缓存fdx、dvd和tip后缀的文件。
low_cost.obs.blockcache.names: ["default", "large"] low_cost.obs.blockcache.default.type: file low_cost.obs.blockcache.default.blockshift: 16 low_cost.obs.blockcache.default.number.blocks.perbank: 4096 low_cost.obs.blockcache.default.bank.count: 30 low_cost.obs.blockcache.default.exclude.file.types: ["fdt"] low_cost.obs.blockcache.large.type: file low_cost.obs.blockcache.large.blockshift: 21 low_cost.obs.blockcache.large.number.blocks.perbank: 1000 low_cost.obs.blockcache.large.bank.count: 5 low_cost.obs.blockcache.large.file.types: ["fdx", "dvd", "tip"]
提升冻结索引的查询性能

仅2023年2月之后创建的、版本为7.6.2或7.10.2的Elasticsearch集群才支持提升冻结索引的查询性能。
在Kibana的Discover页面首次查询冻结索引时,由于此时无任何缓存,导致所有数据均需要从OBS上获取,当命中的数据较多时,需要耗费大量的时间从OBS上获取对应的时间字段以及文件元数据。如果将这一部分数据直接缓存在本地,即可大幅提升查询性能,解决Discover页面首次查询慢的问题。CSS服务就是通过冷数据的本地缓存,实现冻结索引的查询性能提升。本地缓存配置是预置的,用户可以基于业务场景修改配置,也可以查询、了解本地缓存信息。
- 修改冻结索引的本地缓存配置。
表5 本地缓存配置项说明 配置项
类型
scope
是否可动态修改
描述
low_cost.local_cache.max.capacity
Integer
node
是
节点上,能够打开的冷数据缓存的最大数量(每个shard对应一个缓存对象)。
取值范围:10~5000
默认值:500
- 当堆内存使用率一直很高时,可以尝试降低该值。
- 当查询冷数据本地缓存的相关统计指标中“load_overflow_count”数值一直持续快速增加时,建议调大该值。
index.low_cost.local_cache.threshold
Integer
index
是
启用冷数据本地缓存的阈值。
- 当date类型字段的占比小于此值时,启用冷数据本地缓存date类型字段。否则不使用。
- 如果当前索引的date类型字段占据当前索引的绝大部分数据量,则不建议使用此功能。
取值范围:0~100
默认值:50
单位:%
index.low_cost.local_cache.evict_time
字符串
index
是
冷数据的本地缓存的淘汰时间,当缓存时间大于该值,缓存将被删除。根据“index.frozen_date”(冻结成功的时间)判定,当索引无“index.frozen_date”时,则根据索引创建时间判定。
建议根据磁盘用量调整淘汰时长,节省磁盘空间。
取值范围:1d~365d
默认值:30d
单位:天
下面提供了一些修改示例,其中index_name是待修改的索引名称。
- 执行如下命令,修改“low_cost.local_cache.max.capacity”。
PUT _cluster/settings { "persistent": { "low_cost.local_cache.max.capacity":1000 } }
- 执行如下命令,修改“index.low_cost.local_cache.threshold”。
PUT {index_name}/_settings { "index.low_cost.local_cache.threshold":20 }
- 执行如下命令,修改“index.low_cost.local_cache.evict_time”。
PUT {index_name}/_settings { "index.low_cost.local_cache.evict_time":"7d" }
- 查询冻结索引的本地缓存信息。
- 执行如下命令,查询所有节点中冷数据的本地缓存相关指标。
GET /_frozen_stats/local_cache
- 执行如下命令,查询指定节点中冷数据的本地缓存相关指标。
GET /_frozen_stats/local_cache/{node_id}
node_id是集群节点ID。
返回示例:
{ "_nodes" : { "total" : 1, "successful" : 1, "failed" : 0 }, "cluster_name" : "test", "nodes" : { "6by3lPy1R3m55Dcq3liK8Q" : { "name" : "node-1", "transport_address" : "127.0.0.1:9300", "host" : "127.0.0.1", "ip" : "127.0.0.1", "local_cache" : { "get_stats" : { "get_total_count" : 562, //从冷数据本地缓存查询数据的总次数 "get_hit_count" : 562, //从冷数据本地缓存查询数据命中的次数 "get_miss_count" : 0, //从冷数据本地缓存查询数据未命中的次数 "get_total_ns" : 43849200, //从冷数据本地缓存查询数据的总时长 "get_avg_ns" : 78023 //从冷数据本地缓存查询数据的平均时长 }, "load_stats" : { "load_count" : 2, //加载冷数据本地缓存的次数 "load_total_ms" : 29, //加载冷数据本地缓存的总时长 "load_avg_ms" : 14, //加载冷数据本地缓存的平均时长 "load_fail_count" : 0, //加载冷数据本地缓存的失败次数 "load_overflow_count" : 0 //加载冷数据本地缓存时超过缓存池的次数 }, "reload_stats" : { "reload_count" : 0, //重新生成冷数据本地缓存的次数 "reload_total_ms" : 0, //重新生成冷数据本地缓存的总时长 "reload_avg_ms" : 0, //重新生成冷数据本地缓存的平均时长 "reload_fail_count" : 0 //重新生成冷数据本地缓存的失败次数 }, "init_stats" : { "init_count" : 0, //初始化冷数据本地缓存的次数 "init_total_ms" : 0, //初始化冷数据本地缓存的总时长 "init_avg_ms" : 0, //初始化冷数据本地缓存的平均时长 "init_fail_count" : 0 //初始化冷数据本地缓存的失败次数 } } } } }
- 执行如下命令,查询所有节点中冷数据的本地缓存相关指标。
查询存储冷数据的OBS实时速率

仅2023年2月之后创建的、版本为7.6.2或7.10.2的Elasticsearch集群才支持查询存储冷数据的OBS实时速率。
为了更清晰地了解到存算分离的插件在OBS中的使用情况,CSS服务新增了OBS实时速率的统计接口,并且将实时速率记录到系统索引“.freeze_obs_rate-YYYY.mm.dd”中。
OBS实时速率的计算方式:每5秒计算一次,查询前5秒内的平均OBS操作速率。
系统索引“.freeze_obs_rate-YYYY.mm.dd”用于存放OBS操作实时速率和OBS操作数据,便于了解存储冷数据的OBS的操作趋势。该索引的默认保留时间是30天。
- 查询存储冷数据的OBS实时速率。
- 执行如下命令,查询所有节点中存储冷数据的OBS实时速率。
GET _frozen_stats/obs_rate
- 执行如下命令,查询指定节点中存储冷数据的OBS实时速率。
GET _frozen_stats/obs_rate/{node_id}
node_id是集群节点ID。
返回示例:{ "_nodes" : { "total" : 1, "successful" : 1, "failed" : 0 }, "cluster_name" : "test", "nodes" : { "dflDvcSwTJ-fkiIlT2zE3A" : { "name" : "node-1", "transport_address" : "127.0.0.1:9300", "host" : "127.0.0.1", "ip" : "127.0.0.1", "update_time" : 1671777600482, // 当前统计值的更新时间 "obs_rate" : { "list_op_rate" : 0.0, // obs list操作的速率,单位:次/秒 "get_meta_op_rate" : 0.0, // obs get meta操作的速率,单位:次/秒 "get_obj_op_rate" : 0.0, // obs get操作的速率,单位:次/秒 "put_op_rate" : 0.0, // obs put操作的速率,单位:次/秒 "obs_total_op_rate" : 0.0, // obs所有操作的速率,单位:次/秒 "obs_upload_rate" : "0.0 MB/s", // obs上传数据的速率,MB/秒 "obs_download_rate" : "0.0 MB/s" // obs下载数据的速率,MB/秒 } } } }
- 执行如下命令,查询所有节点中存储冷数据的OBS实时速率。
- 修改存储OBS实时速率的索引“.freeze_obs_rate-YYYY.mm.dd”的保留时间。索引的默认保留时间是30天。
执行如下命令,将索引保留时间改成7天。
PUT _cluster/settings { "persistent": { "low_cost.obs_rate_index.evict_time": "7d" } }
表6 配置项说明 配置项
类型
scope
是否可动态修改
说明
low_cost.obs_rate_index.evict_time
String
node
是
用于控制索引“.freeze_obs_rate-YYYY.mm.dd”的保留时间。
- 取值范围:1d~365d
- 默认值:30d
- 单位:天
相关文档
- 如果业务需兼顾冷数据的查询性能(如定期检索历史数据),可参见切换Elasticsearch集群冷热数据采用冷热分层方案。
- 结合索引生命周期管理可以实现自动存算分离,可参见通过索引生命周期管理实现Elasticsearch集群存算分离。