2. 节点查询缓存(Node Query Cache):工作原理、参数配置与调优

2.1 工作原理

节点查询缓存(Node Query Cache,简称 Query Cache)是 Elasticsearch 在每个节点级别维护的缓存,用于缓存 过滤上下文(Filter Context) 中查询子句的结果集(文档 ID 位图)。当同一个过滤条件被多次执行时,可以直接从缓存中读取匹配的文档 ID,避免重复遍历倒排索引。

核心机制: Query Cache 只缓存 filter 上下文中的查询(如 bool.filter、constant_score.filter、post_filter),不缓存 query 上下文中的评分查询(如 match、term 查询且未包装在 filter 中)。

每个分片(Shard)在其所在的节点上拥有独立的 Query Cache 实例。缓存键由 分片 ID + 查询子句的哈希值 组成。当分片发生 refresh、merge 或 segment 被删除时,该分片对应的 Query Cache 条目会被自动失效。

节点查询缓存(Query Cache)工作原理 查询请求(filter) 协调节点分发 数据节点:分片级别查询执行 缓存命中? 返回缓存位图 遍历倒排索引 写入缓存 + 返回结果 缓存失效条件: refresh / merge / segment 删除

2.2 参数配置:indices.queries.cache.size

该参数控制节点级别 Query Cache 的最大堆内存占比或绝对值。配置方式为 动态集群设置,支持百分比或具体字节值。

配置项 默认值 可选值示例 说明
indices.queries.cache.size 10% 5%、256mb、1g 节点堆内存的百分比或绝对大小
indices.queries.cache.count 10000 5000、20000 每个节点缓存的最大条目数(7.x+ 已废弃)
配置建议: 对于过滤查询密集的业务场景(如仪表盘、固定范围筛选),建议将 indices.queries.cache.size 设置为堆内存的 10%~20%。对于写入密集型或过滤查询较少的场景,可降低至 5% 或 256MB。

动态更新示例:

# 设置为堆内存的 15%
PUT _cluster/settings
{
  "persistent": {
    "indices.queries.cache.size": "15%"
  }
}

# 设置为绝对大小 512MB
PUT _cluster/settings
{
  "transient": {
    "indices.queries.cache.size": "512mb"
  }
}

2.3 监控指标

通过节点统计 API 和 cat API 可以获取 Query Cache 的实时状态。

监控指标 API 路径 关键字段 说明
缓存大小 GET _nodes/stats/indices/query_cache memory_size_in_bytes 当前 Query Cache 占用的内存
命中率 GET _nodes/stats/indices/query_cache hit_count / total_count 缓存命中次数与总查询次数之比
逐出次数 GET _nodes/stats/indices/query_cache evictions 因内存不足或条目数超限被逐出的次数
缓存条目 GET _cat/nodes?v&h=name,qc, qcm qc(缓存条目数) 每个节点当前的缓存条目数量

监控命令示例:

# 查看所有节点的 Query Cache 统计
GET _nodes/stats/indices/query_cache?human

# 查看特定节点的缓存命中与逐出
GET _nodes/nodeId1,nodeId2/stats/indices/query_cache

# 使用 cat API 快速查看
GET _cat/nodes?v&h=name,queryCacheMemory,queryCacheHitCount,queryCacheEvictions

2.4 调优策略

注意: Query Cache 的调优需要结合业务查询模式。过度依赖缓存可能导致内存浪费,而缓存过小则会导致频繁逐出,降低命中率。
  1. 增大缓存空间: 当 evictions 持续增长且命中率低于 50% 时,适当增加 indices.queries.cache.size。
  2. 优化查询结构: 将高频过滤条件放入 bool.filter 或 constant_score.filter,确保能被缓存。
  3. 避免缓存污染: 对于低基数或高基数的唯一值过滤(如 UUID),缓存收益低,可考虑使用 index.query_cache.enabled: false 按索引禁用。
  4. 分片数量控制: 每个分片独立维护缓存,分片过多会分散缓存内存,建议单节点分片数控制在 200~500 以内。
  5. 监控与告警: 设置 evictions 的告警阈值,当每分钟逐出次数超过 100 时触发扩容或调参。
Query Cache 调优决策流程 监控 evictions 与命中率 命中率 < 50%? 增大 cache.size 检查查询是否在 filter 中 持续监控:每 5 分钟采集一次 evictions 和命中率 结合分片数量与堆内存综合评估

2.5 常见问题与避坑

问题 原因 解决方案
缓存命中率极低(< 10%) 查询未使用 filter 上下文;查询条件频繁变化 将高频查询改为 bool.filter;使用 constant_score 包装
evictions 持续增长 缓存空间不足;分片过多导致缓存碎片化 增大 indices.queries.cache.size;合并小分片
内存占用过高 缓存了过多低效查询结果(如大位图) 按索引禁用缓存:index.query_cache.enabled: false
缓存不一致 分片 refresh 后缓存未及时失效(极少见) 手动清除缓存:POST _cache/clear?query=true
最佳实践: 在 Kibana 监控面板中创建 Query Cache 仪表盘,重点关注 memory_size_in_bytes 和 evictions 两个指标。当 evictions 超过 1000/分钟 时,建议立即调整缓存配置或优化查询结构。