Elasticsearch 查询缓存 cleared 频繁导致性能下降怎么解决?

文章导读
查询缓存频繁 cleared 通常意味着缓存失效速度超过了复用速度,重点在于区分是 segment merge 导致还是容量不足导致。本文基于 Elasticsearch 6.x 及以上版本,优先调整缓存大小或优化写入策略。
📋 目录
  1. 版本与兼容性说明
  2. 命令速用版
  3. 为什么会这样
  4. 分步处理
  5. 怎么验证是否生效
  6. 常见坑
A A

查询缓存频繁 cleared 通常意味着缓存失效速度超过了复用速度,重点在于区分是 segment merge 导致还是容量不足导致。本文基于 Elasticsearch 6.x 及以上版本,优先调整缓存大小或优化写入策略。

先说结论:大部分情况是缓存容量不足或写入过于频繁导致 segment 合并,先确认缓存命中率再调整配置。

  • 先定位:通过 _stats 接口查看 evictions 和 memory_size_in_bytes 判断是容量淘汰还是索引变更导致。
  • 先做:优先使用索引级配置调大 indices.queries.cache.size,或减少高频写入导致的 segment 合并。
  • 再验证:观察 cleared 次数增长是否放缓,同时确认命中率没有因缓存过大而下降。

版本与兼容性说明

本文操作适用于 Elasticsearch 6.x、7.x 及 8.x 版本。不同版本间缓存机制基本一致,但默认堆内存比例可能略有差异。生产环境调整前建议在测试集群验证。

命令速用版

注意:以下命令请根据实际索引名替换 <index>。全局调整需谨慎,优先推荐索引级配置。

# 1. 查看查询缓存统计(关注 evictions 和 memory_size_in_bytes)
GET /_stats/query_cache

# 2. 查看当前缓存配置值
GET /_settings?include_defaults=true&filter_path=**.queries.cache

# 3. 调整缓存大小(索引级推荐,避免影响其他业务)
PUT /<index>/_settings
{
  "index.queries.cache.size": "15%"
}

# 4. 调整刷新间隔(减少 segment 合并频率)
PUT /<index>/_settings
{
  "index.refresh_interval": "30s"
}

为什么会这样

Elasticsearch 的查询缓存(Query Cache)主要存储 filter 上下文的查询结果。缓存 cleared 频繁通常有两个核心原因:一是缓存空间不足,旧条目被强制淘汰(eviction);二是底层索引段(segment)发生了合并或刷新,导致依赖该段的缓存条目失效。

当写入频繁时,segment 合并也会频繁,这会连带清空相关缓存。另外,如果查询基数过大或区分度太高,缓存复用率低,也会显得 cleared 频繁但实际无益。

分步处理

1. 确认缓存状态与配置

执行 GET /_stats/query_cache,关注 evictionsmemory_size_in_bytes。如果 evictions 增长快且 memory_size_in_bytes 接近上限,说明是容量问题。同时使用 GET /_settings?include_defaults=true&filter_path=**.queries.cache 确认当前配置值。

2. 调整缓存大小

默认配置通常为堆内存的 10%。如果确认是容量不足,可逐步调大 index.queries.cache.size。建议优先使用索引级设置,避免全局调整 indices.queries.cache.size 影响其他低负载索引。

3. 检查写入频率

如果业务允许,调整 refresh_interval 或合并策略,减少 segment 合并频率。对于日志类场景,考虑按天索引,避免单个索引频繁变更。具体命令见上方“命令速用版”。

Elasticsearch 查询缓存 cleared 频繁导致性能下降怎么解决?

4. 优化查询语句

确保高频查询使用了 filter 上下文。sort、aggregation 或非确定性查询不会进入查询缓存。以下是对比示例:

// 不会进入查询缓存(Query 上下文)
{
  "query": {
    "match": { "status": "active" }
  }
}

// 会进入查询缓存(Filter 上下文)
{
  "query": {
    "bool": {
      "filter": {
        "term": { "status": "active" }
      }
    }
  }
}

怎么验证是否生效

调整后再次执行 GET /_stats/query_cache,对比 evictions 的增长速率。如果单位时间内的淘汰次数明显下降,且 hit_count 占比稳定或上升,说明优化有效。

同时监控节点堆内存使用情况,确保调整缓存大小没有导致 OOM 或频繁 GC。

常见坑

1. 混淆缓存类型

查询缓存不同于 Field Data 缓存。排序和聚合使用的是 Field Data,调整查询缓存大小对它们无效。

2. 盲目调大缓存

缓存过大可能导致清理单次耗时增加,甚至影响查询延迟。需根据实际监控调整,避免占用过多堆内存。

3. 忽略查询特征

如果查询条件包含时间戳或高基数字段,缓存命中率天然很低,此时 cleared 频繁是正常现象,不应强行优化缓存,而应考虑优化查询逻辑。