Skip to content
缓存、消息与检索故障排查 · 第 4 篇 / 共 5 篇
领域生产问题
专题数据与基础设施排障专题
当前序列缓存、消息与检索故障排查
阅读位置第 4 篇 / 共 5 篇当前专题第 2 个序列 / 共 5 个序列

Elasticsearch 查询突然变慢时怎么定位

Elasticsearch 慢查询是线上非常典型的一类问题,因为业务看到的往往只是一个结果:

  • 搜索结果半天出不来
  • 聚合接口开始超时
  • 应用线程堆满在 ES 调用上
  • 首页、搜索页、日志检索页一起抖

这类故障最怕两种误判:

  • 一上来就把节点加倍,却没看到慢的是某几类重查询
  • 一上来只盯 ES 机器,却没看到问题其实来自写入高峰、索引膨胀或查询模型突变

先说结论

  • ES 变慢时先判断是单类查询变慢,还是整个集群都在退化
  • 第一目标是止血,限制最重的查询和最危险的时间范围,不要让慢请求把应用也拖死
  • 第二目标是判断瓶颈在查询模型、字段设计、分片布局、写入高峰还是资源争抢
  • 很多 ES 慢查询不是参数问题,而是深分页、高基数聚合、脚本查询和动态字段膨胀叠加出来的结果

一个典型故障现场

以一个商品搜索系统为例,工作日白天搜索接口 P95 一直在 80ms 左右,某天下午突然出现:

  • 搜索页 RT 从 80ms 升到 1.5s
  • 聚合筛选接口大量超时
  • 应用侧线程池开始堆积
  • ES 节点 CPU 飙高,但并不是所有节点都一样高
  • 同时恰好有一批商品数据正在批量重建索引

这时如果只看“CPU 高了”,很容易遗漏真正关键的问题:

  • 是查询变重了
  • 还是写入和查询抢资源
  • 是所有索引一起慢
  • 还是少数大索引、热索引在拖垮整体

第一阶段:先止血,不要让慢查询拖跨应用

1. 先限制最危险的查询入口

如果你已经看到:

  • 深分页请求很多
  • 时间范围查询被放大到近 30 天或 90 天
  • 某类筛选页带了很多高基数聚合

先在应用层或网关侧限一下:

  • 最大分页深度
  • 最大时间范围
  • 复杂聚合开关
  • 某些高成本排序

这一步的意义不是“治好 ES”,而是先把最贵的请求压下来。

2. 看是否要临时降级聚合或推荐模块

很多搜索页真正昂贵的不是主搜索本身,而是:

  • 侧边栏聚合
  • 推荐词
  • 联想词
  • 多维筛选统计

如果业务允许,先把这些附加能力降级,通常比盲目扩容更快见效。

3. 避免应用线程被 ES 调用一直占满

如果 ES 已经明显抖动,应用侧也要尽快启用:

  • 更严格的超时
  • 隔离线程池
  • 熔断降级
  • 缓存兜底

否则 ES 慢查询很快就会演变成应用整体不可用。

第二阶段:先判断是“局部慢”还是“整体退化”

这一步非常关键,因为两种场景的排查方向完全不同。

1. 如果只有少数接口变慢

更像是:

  • 某类 DSL 最近变复杂了
  • 某些索引 Mapping 出了问题
  • 某几个字段聚合、排序特别重
  • 某个新功能放开了深分页或脚本查询

2. 如果所有查询都在变慢

更像是:

  • 集群资源整体紧张
  • 写入和查询发生激烈竞争
  • shard 过多或热点集中
  • 磁盘、合并、刷新、GC 同时在抖

很多时候只要先分清这一步,定位速度就会快一大截。

第三阶段:看四组最关键的排查线索

1. 查询类型有没有明显变化

先看慢的是哪类请求:

  • matchbool 这类普通搜索
  • 大范围聚合
  • 深分页
  • 排序
  • 脚本查询

如果慢请求只集中在某一类,通常先从 DSL 和字段设计下手,而不是从集群层面大动干戈。

2. 索引和时间范围有没有放大

很多线上慢查询不是 DSL 写坏了,而是命中的范围突然变大:

  • 原来查近 1 天,后来放开成近 30 天
  • 原来只打一个索引别名,现在扫了一组滚动索引
  • 原来按租户过滤,现在某次改版把过滤条件漏掉了

一旦检索范围放大,ES 的扫描和聚合成本会非常明显。

3. 写入侧是不是也在同一时间抖

如果恰好同时出现:

  • 批量导入
  • 索引重建
  • refresh/merge 压力升高
  • 副本同步和段合并增多

那就要警惕“查询慢并不是单独发生”,而是查询和写入正在争资源。

4. 热点是不是集中在少数 shard 或少数节点

如果只有个别节点持续很高,通常要看:

  • 某些 shard 是否过热
  • 某些索引是否集中落在少数节点
  • 查询是否反复命中热点索引

这类问题用“整集群平均指标”很容易看不出来。

常见根因画像

1. 深分页和大时间范围一起出现

最典型,也最常见。管理后台、运营报表、日志检索页很容易把 ES 当数据库列表页来用。

2. 高基数字段做重聚合

比如对用户 ID、设备 ID、订单号这类字段做大范围聚合,再叠加排序和筛选,成本非常高。

3. Mapping 膨胀或动态字段失控

字段数量越来越多、嵌套层级越来越乱时,查询和聚合都会越来越重,写入成本也会上升。

4. 写入高峰和查询高峰重叠

批量导入、索引重建、热点更新和用户查询同时发生时,集群会明显抖动。

5. shard 过多或索引拆得过碎

很多系统不是单个索引太大,而是“小 shard 太多”,协调开销和管理开销一起上来。

一个更实用的排查顺序

线上 ES 变慢时,我通常按这个顺序判断:

  1. 先看是单类接口慢,还是整站检索都慢。
  2. 再看慢请求的 DSL 类型,是聚合、深分页、排序还是脚本。
  3. 看命中的索引范围、时间范围、租户范围有没有被放大。
  4. 看同一时间段写入、refresh、merge 是否也在上升。
  5. 看热点是否集中在少数节点、少数 shard。
  6. 最后再决定是先改查询、降范围、拆索引,还是临时扩资源。

这个顺序能避免一开始就把问题归因到“ES 不行了”。

止血后的治理方向

1. 给高成本查询设硬边界

包括:

  • 最大时间范围
  • 最大分页深度
  • 高基数聚合白名单
  • 脚本查询限制

2. 让索引模型更贴近查询路径

字段该用 keyword 还是 text,该不该支持聚合、排序、多字段,要提前规划。

3. 把写入高峰和查询高峰尽量错开

批量导入、重建索引、补数据这类动作,最好别和核心检索高峰撞在一起。

4. 做慢查询基线和热点索引监控

不要等接口超时了才知道 ES 有问题,最好平时就能看到:

  • 哪类查询最贵
  • 哪些索引最热
  • 哪些节点最偏

总结

Elasticsearch 慢查询的关键,不是看到 RT 变高就先扩容,而是先判断:

  • 是哪些请求变慢了
  • 范围是不是被放大了
  • 写入是不是也在抢资源
  • 热点是不是集中在局部

把“查询模型、索引范围、写入竞争、热点分布”这四条线理顺后,ES 慢查询问题通常都会从模糊的性能波动,变成可定位、可止血、可治理的工程问题。

延伸阅读相关文章优先当前专题,再补跨专题关联。
同一序列 · 回看前文会更完整ClickHouse 查询超时怎么排查适合把 Redis 热点、Kafka 积压、ES 慢查询和 ClickHouse 超时放在一条排障线上看。应用运行时排障专题 · 应用运行时典型故障案例同一序列 · 回看前文会更完整Kafka 积压突然飙升时怎么排查适合把 Redis 热点、Kafka 积压、ES 慢查询和 ClickHouse 超时放在一条排障线上看。应用运行时排障专题 · 应用运行时典型故障案例同专题其他序列 · 共享标签:案例排障接口 RT 飙升但 CPU 不高时怎么排查适合把 CPU、Full GC、线程池和接口超时这类应用层异常放在一组里看。应用运行时排障专题 · 应用运行时异常排查同专题其他序列 · 共享标签:案例排障接口超时排查为什么要区分 RT 和 queue wait适合把线程死锁、CPU 高、Full GC、接口超时和 OOM 现场保留放在一条运行时排障主线上看。应用运行时排障专题 · 应用运行时故障的现场与根因收敛跨专题关联 · 共享标签:Elasticsearch、案例排障Elasticsearch 集群发黄时先别急着重平衡适合把 Redis 抖动、MySQL 连接打满、MQ 积压、ES 发黄、ClickHouse 合并堆积和磁盘打满放在同一条基础设施排障主线上看。数据与基础设施排障专题 · 数据与基础设施故障的分层排查跨专题关联 · 共享标签:Elasticsearch、案例排障MySQL 索引设计与慢 SQL 排查适合先把字段设计、索引、Explain、分页和慢 SQL 这条主线走顺。MySQL 专题 · MySQL 建模与查询优化
继续阅读缓存、消息与检索故障排查当前序列第 4 篇 / 共 5 篇当前专题第 2 个序列 / 共 5 个序列
往前看
上一篇Kafka 积压突然飙升时怎么排查回到当前序列上一章上一序列数据库与网关故障排查从第 1 篇开始:MySQL 连接数打满时怎么排查
往后看
下一篇ClickHouse 查询超时怎么排查继续当前序列下一章下一序列容器与编排异常排查从第 1 篇开始:Kubernetes Pod Pending 时怎么排查

把零散经验整理成可查、可复用、可持续更新的企业级知识门户