> 技术文档 > Elasticsearch 缓存全解析:原理、监控与优化实战

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:推荐使用 keyworddoc_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 memory JVM Heap 小型数据结构缓存 Doc values OS 页缓存 支持聚合、排序、脚本 OS page cache 操作系统 文件系统层面的内存缓存

关键点

  • segment cache 不在 ES 层直接管理

  • Doc values 对 heap 压力小,但对 OS 缓存敏感


1.5 Circuit Breaker(内存保护机制)

  • Fielddata breaker:防止 fielddata 占用过多堆

  • Request breaker:限制请求缓存和聚合计算的堆使用

  • 当内存使用超限,触发异常保护节点不被 OOM

查看 breaker 状态

GET /_nodes/stats/breaker

1.6 缓存生命周期与触发机制

缓存类型 触发方式 回收/驱逐机制 Fielddata 第一次访问字段 LRU 或 circuit breaker Query Cache 第一次查询 LRU 或手动清理 Request Cache 第一次搜索请求 索引更新时自动失效 Segment Cache Segment 加载 OS 自动回收

小结:理解各缓存的触发条件与驱逐策略是缓存优化的基础,避免堆 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 fielddata 堆内存占用 > 50% 堆报警 elasticsearch_nodes_indices_query_cache_hit_count_total query cache 命中次数累计 高 miss 提示缓存低效 elasticsearch_nodes_indices_request_cache_memory_size_bytes request cache 占用内存 可用于评估缓存命中率 elasticsearch_nodes_breakers_fielddata_estimated_size_bytes fielddata breaker 估算内存 高风险 > 阈值

提示:结合 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. 定期采集指标:建议每 1~5 分钟采集一次 fielddata、query cache、request cache 占用

  2. 设置告警阈值

    • fielddata 使用超过 50% 堆时报警

    • query cache miss 高于 40% 时分析缓存策略

  3. 结合 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 清理策略与最佳实践

  1. Fielddata

    • 高基数字段聚合后,定期清理 fielddata

    • 避免长时间占用堆内存

  2. Query Cache

    • 对热点查询有效

    • 若命中率低,可禁用索引级 query cache

  3. Request Cache

    • 热索引可开启 request cache

    • 写入密集型索引建议禁用以降低缓存失效频率

  4. 全局清理

    • 在低峰期或维护窗口执行

    • 避免一次性清理所有节点导致瞬时负载激增


3.7 命令总结(REST API)

缓存类型 清理命令 动态关闭 Fielddata POST /index/_cache/clear?fielddata=true N/A Query Cache POST /index/_cache/clear?query=true PUT /index/_settings { \"index.queries.cache.enabled\": false } Request Cache POST /index/_cache/clear?request=true PUT /index/_settings { \"index.requests.cache.enable\": false } 全部 POST /_cache/clear?fielddata=true&query=true&request=true N/A