Elasticsearch 缓存全解析:原理、监控与优化实战
Elasticsearch 缓存概览与分类
本章摘要
本章介绍 Elasticsearch 中各种缓存类型及其工作原理,分析缓存生命周期、触发机制以及版本差异,帮助读者对 ES 缓存有全面认知。
1.1 Fielddata / Fielddata Cache
Fielddata 是 Elasticsearch 在执行排序、聚合时,将倒排索引中的文本字段(text)加载到堆内存(Heap)中的数据结构。它主要用于支持:
-
聚合(Aggregation):统计、分桶
-
排序(Sort)
-
脚本计算(Script)
示例:查看 fielddata 使用情况
GET /_nodes/stats/indices/fielddata
快速结果预览(JSON 字段说明)
{ \"nodes\": { \"node-id\": { \"indices\": { \"fielddata\": { \"memory_size_in_bytes\": 10485760, \"evictions\": 5 } } } }}
-
memory_size_in_bytes
:当前 fielddata 占用堆内存大小 -
evictions
:被驱逐的缓存条目数
版本差异:
-
ES 6.x:fielddata 默认关闭 text 字段,需要
fielddata=true
-
ES 7.x / 8.x:推荐使用
keyword
或doc_values
避免大量 fielddata
优化建议:
-
尽量使用
keyword
字段或doc_values
替代 text 字段 -
设置 JVM 堆大小与 fielddata breaker 避免 OOM
1.2 Query Cache(查询缓存)
Query Cache 曾用于过滤器结果缓存,提高重复查询性能。不同版本有以下变化:
-
ES 6.x / 7.x:存在 filter cache 历史概念
-
ES 7.x / 8.x:filter cache 被合并进 query cache
-
ES 8.x:request-level query cache 更智能,支持 shard 层级缓存
示例:查看 query cache 状态
GET /_stats/query_cache
快速结果预览
\"query_cache\": { \"memory_size_in_bytes\": 102400, \"total_count\": 200, \"hit_count\": 150, \"miss_count\": 50}
-
hit_count / total_count
用于计算缓存命中率
1.3 Request Cache(索引请求缓存)
Request Cache 针对 search request
的 shard 结果缓存,主要用于频繁重复查询。
GET /my_index/_search?request_cache=true{ \"query\": { \"term\": { \"status\": \"active\" } }}
-
默认 ES 6.x:request cache 默认关闭
-
ES 7.x / 8.x:request cache 默认开启,可针对索引动态关闭
1.4 Shard / Segment 缓存
Elasticsearch 的底层数据结构是 segment,每个 segment 都有缓存机制:
关键点:
-
segment cache 不在 ES 层直接管理
-
Doc values 对 heap 压力小,但对 OS 缓存敏感
1.5 Circuit Breaker(内存保护机制)
-
Fielddata breaker:防止 fielddata 占用过多堆
-
Request breaker:限制请求缓存和聚合计算的堆使用
-
当内存使用超限,触发异常保护节点不被 OOM
查看 breaker 状态:
GET /_nodes/stats/breaker
1.6 缓存生命周期与触发机制
小结:理解各缓存的触发条件与驱逐策略是缓存优化的基础,避免堆 OOM 和性能下降。
缓存监控与指标查询
本章摘要
本章介绍如何通过 Elasticsearch API 和外部监控工具(Grafana/Prometheus)实时查看各类缓存状态,包括 fielddata、query cache、request cache、segment/ shard 缓存,并解析关键指标的含义,帮助工程师快速定位性能瓶颈。
2.1 使用 Elasticsearch 内置 API 查询缓存指标
Elasticsearch 提供多种 API 来获取节点和索引的缓存状态:
2.1.1 _nodes/stats
获取节点缓存信息
GET /_nodes/stats/indices/fielddata,query_cache,request_cache
示例输出(关键字段解释):
{ \"nodes\": { \"node-id\": { \"indices\": { \"fielddata\": { \"memory_size_in_bytes\": 10485760, \"evictions\": 5 }, \"query_cache\": { \"memory_size_in_bytes\": 204800, \"total_count\": 300, \"hit_count\": 210, \"miss_count\": 90 }, \"request_cache\": { \"memory_size_in_bytes\": 51200, \"evictions\": 3, \"hit_count\": 25, \"miss_count\": 10 } } } }}
-
memory_size_in_bytes
:缓存占用堆内存大小 -
evictions
:被驱逐条目数 -
hit_count / miss_count
:命中率分析
版本差异:
ES 6.x:query_cache 默认不缓存所有查询,需要手动开启
ES 7.x / 8.x:query_cache 自动启用,但可通过索引设置动态关闭
2.1.2 _stats
获取索引级缓存
GET /my_index/_stats
输出片段:
{ \"_all\": { \"primaries\": { \"fielddata\": { \"memory_size_in_bytes\": 1048576, \"evictions\": 1 }, \"query_cache\": { \"memory_size_in_bytes\": 10240, \"total_count\": 50, \"hit_count\": 35 } } }}
解读:
-
_all.primaries
:主分片缓存情况 -
_all.total
:包括主分片和副本分片 -
通过对比可发现热点索引分片缓存压力
2.1.3 _cat
API 查询缓存简表
GET /_cat/indices?v&h=index,docs.count,store.size,fielddata.memory_size,query_cache.memory_size,request_cache.memory_size
快速结果示例:
index docs.count store.size fielddata.memory_size query_cache.memory_size request_cache.memory_sizemy_index 1000000 2gb 10mb 20mb 5mb
_cat
输出直观,便于快速发现缓存占用过高的索引
2.2 Grafana / Prometheus 常用缓存指标
在生产环境中,Grafana + Prometheus 常用于可视化缓存指标,常用指标及含义如下:
elasticsearch_nodes_indices_fielddata_memory_size_bytes
elasticsearch_nodes_indices_query_cache_hit_count_total
elasticsearch_nodes_indices_request_cache_memory_size_bytes
elasticsearch_nodes_breakers_fielddata_estimated_size_bytes
提示:结合 JVM heap 使用率和 cache 命中率,可判断是否需要调优缓存策略
2.3 JSON 输出解析示例
示例 _nodes/stats
输出片段:
\"fielddata\": { \"memory_size_in_bytes\": 10485760, \"evictions\": 5}
-
memory_size_in_bytes:当前缓存占用堆内存 10MB
-
evictions:LRU 驱逐了 5 个条目
-
分析:如果频繁 evictions,说明缓存压力大,可能导致频繁重建 fielddata
\"query_cache\": { \"memory_size_in_bytes\": 204800, \"total_count\": 300, \"hit_count\": 210, \"miss_count\": 90}
-
hit_count / total_count ≈ 70%,命中率适中
-
若 hit_count 占比低,可考虑禁用 request cache 或优化查询重复率
2.4 Kibana Dev Tools 示例
在 Kibana 中同样可直接运行:
GET _nodes/stats/indices/fielddata,query_cache,request_cache
优势:
-
支持 JSON 高亮与折叠
-
可结合 Kibana Dashboard 绘制缓存趋势曲线
-
快速定位热点索引与节点
2.5 监控最佳实践
-
定期采集指标:建议每 1~5 分钟采集一次 fielddata、query cache、request cache 占用
-
设置告警阈值:
-
fielddata 使用超过 50% 堆时报警
-
query cache miss 高于 40% 时分析缓存策略
-
-
结合 JVM heap 监控:缓存高占用 + heap 高占用时,优先分析 fielddata/segment cache
缓存操作与清理实战
本章摘要
本章介绍 Elasticsearch 中各种缓存的清理、刷新与禁用操作,涵盖 fielddata、query cache、request cache 等常用缓存类型,并针对 ES 6.x、7.x、8.x 给出命令差异与实际操作示例,帮助运维工程师在生产环境中安全执行缓存管理。
3.1 清理 Fielddata Cache
Fielddata 占用堆内存较大,高基数字段聚合或排序容易触发 OOM。可以通过 API 清理:
POST /my_index/_cache/clear?fielddata=true
快速结果预览:
{ \"_shards\": { \"total\": 5, \"successful\": 5, \"failed\": 0 }}
-
fielddata=true
:只清理 fielddata -
支持索引级清理或全局清理(
_all
或*
)
Kibana Dev Tools 示例:
POST /_all/_cache/clear?fielddata=true
版本差异:
-
ES 6.x / 7.x / 8.x 基本相同,字段缓存清理 API 保持一致
3.2 清理 Query Cache
Query Cache 主要缓存过滤器结果,适用于重复查询。可以针对索引或全局清理:
POST /my_index/_cache/clear?query=true
快速结果预览:
{ \"_shards\": { \"total\": 5, \"successful\": 5, \"failed\": 0 } }
-
query=true
:清理 query cache -
注意:清理 query cache 会增加下一次查询延迟
动态关闭 query cache(索引级别):
{ \"_shards\": { \"total\": 5, \"successful\": 5, \"failed\": 0 }}
ES 6.x / 7.x / 8.x 差异:
ES 6.x 默认 query cache 可选择关闭
ES 7.x / 8.x 默认开启,支持索引级动态关闭
3.3 清理 Request Cache
Request Cache 缓存 shard 级搜索请求结果,清理方法如下:
POST /my_index/_cache/clear?request=true
快速结果预览:
{ \"_shards\": { \"total\": 5, \"successful\": 5, \"failed\": 0 }}
-
ES 6.x:默认 request cache 关闭,需要显式开启
-
ES 7.x / 8.x:默认 request cache 开启,可在索引设置禁用
动态禁用 request cache:
PUT /my_index/_settings{ \"index.requests.cache.enable\": false}
3.4 全局缓存清理
可以一次性清理所有缓存类型:
POST /_cache/clear?fielddata=true&query=true&request=true
快速结果预览:
{ \"_shards\": { \"total\": 15, \"successful\": 15, \"failed\": 0 }}
运维注意:
全局清理可能导致短时间搜索延迟上升
建议在低峰期执行或分批清理热点索引
3.6 清理策略与最佳实践
-
Fielddata:
-
高基数字段聚合后,定期清理 fielddata
-
避免长时间占用堆内存
-
-
Query Cache:
-
对热点查询有效
-
若命中率低,可禁用索引级 query cache
-
-
Request Cache:
-
热索引可开启 request cache
-
写入密集型索引建议禁用以降低缓存失效频率
-
-
全局清理:
-
在低峰期或维护窗口执行
-
避免一次性清理所有节点导致瞬时负载激增
-
3.7 命令总结(REST API)
POST /index/_cache/clear?fielddata=true
POST /index/_cache/clear?query=true
PUT /index/_settings { \"index.queries.cache.enabled\": false }
POST /index/_cache/clear?request=true
PUT /index/_settings { \"index.requests.cache.enable\": false }
POST /_cache/clear?fielddata=true&query=true&request=true