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 条目会被自动失效。
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 的调优需要结合业务查询模式。过度依赖缓存可能导致内存浪费,而缓存过小则会导致频繁逐出,降低命中率。
- 增大缓存空间: 当
evictions持续增长且命中率低于 50% 时,适当增加indices.queries.cache.size。 - 优化查询结构: 将高频过滤条件放入
bool.filter或constant_score.filter,确保能被缓存。 - 避免缓存污染: 对于低基数或高基数的唯一值过滤(如 UUID),缓存收益低,可考虑使用
index.query_cache.enabled: false按索引禁用。 - 分片数量控制: 每个分片独立维护缓存,分片过多会分散缓存内存,建议单节点分片数控制在 200~500 以内。
- 监控与告警: 设置
evictions的告警阈值,当每分钟逐出次数超过 100 时触发扩容或调参。
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/分钟 时,建议立即调整缓存配置或优化查询结构。