中间件-03-Elasticsearch集群测试与监控方法

在接手 Elasticsearch 集群时,最先完成的动作通常是下面这些:

  • 集群节点都拉起来,green 状态能看到
  • 索引能创建,文档能写进去
  • Kibana 或管理页面能查到数据
  • 监控里已经接入 CPU、内存、磁盘和 JVM

这些动作只能说明集群“已经启动”,远远不等于“已经可用”。
Elasticsearch 在测试和平台场景里最容易出现的误判,是把下面几件事混为一谈:

  • 节点在线,等于查询和写入都稳定
  • 集群是 green,等于性能没有风险
  • 写入成功,等于副本和刷新链路都正常
  • 查询能返回结果,等于分片、缓存和磁盘没有问题

真实现场里,Elasticsearch 更像一个会把写入模型、查询模型、分片策略、磁盘策略和恢复过程全部放大的系统。一旦验证方法和监控口径不成体系,就很容易出现下面这些情况:

  • 压测时写入吞吐明显下降,但业务只看到“ES 变慢了”
  • 查询耗时抖动很大,却分不清是 DSL 设计问题、分片问题还是节点热点
  • 集群仍然是 yellowgreen,但磁盘水位已经逼近阈值,后续扩容和恢复都变得被动
  • 节点重启后数据能恢复,但恢复期间写入和查询都开始退化,现场却没有被提前识别

所以这篇文章只讨论一个核心问题:

Elasticsearch 集群在测试与平台场景里,应该怎么做验证、监控、执行和排障,才能真正回答“这个集群能不能稳定承载业务”。

一、先把验证对象分层,不要把“集群可用”理解成一个结果

Elasticsearch 集群测试最容易失控的原因,不是测试项太少,而是没有先分层。
更适合现场落地的方式,是先把验证对象拆成五层:

  • 集群层:节点角色、选主、健康状态、分片分布、恢复状态
  • 索引层:模板、映射、分片数、副本数、生命周期、刷新策略
  • 写入层:批量写入、单条写入、刷新延迟、拒绝写入、堆积情况
  • 查询层:典型 DSL、聚合、分页、排序、过滤、热点查询
  • 运维层:磁盘水位、JVM、线程池、合并、迁移、扩容、节点故障恢复

只有把这五层拆开,后面才能回答清楚:

  • 是集群层就不稳,还是索引策略先埋了坑
  • 是写入链路扛不住,还是查询模型把热点打出来了
  • 是正常压力下的性能瓶颈,还是恢复过程带来的阶段性退化

如果一开始就只做“建索引、写数据、查结果”这种功能式验证,后面几乎一定会漏掉分片倾斜、刷新放大、磁盘水位、线程池堆积这些真正影响稳定性的点。

二、验证分层应该怎么做,才不会只剩功能检查

1. 集群层:先看集群是不是进入了稳定状态

集群层验证的目标,不是看 /_cluster/health 返回 green 就结束,而是确认下面几件事:

  • 所有预期节点是否都已加入集群
  • master 是否稳定,没有频繁切换
  • 分片是否均衡落到预期节点
  • 节点重启后分片恢复是否过慢
  • 数据节点、协调节点、master 节点职责是否清晰

更适合的检查顺序通常是:

  1. /_cat/nodes?v
  2. /_cluster/health
  3. /_cat/shards?v
  4. /_cat/allocation?v
  5. /_cluster/pending_tasks

这里最常见的误判有两个:

  • green 就认为没有问题,实际分片分布已经严重不均
  • 节点数看起来正常,实际 master 切换频繁,集群一直在恢复边缘

2. 索引层:重点看模板和映射是否已经埋雷

很多 ES 集群不是死在节点,而是死在索引策略。
索引层至少要确认:

  • 索引模板是否按业务分层,而不是所有索引共用一套粗放配置
  • 分片数和副本数是否匹配真实数据量与节点数
  • 映射是否明确,避免动态字段无限膨胀
  • 是否存在高基数字段被错误设成可聚合字段
  • 生命周期策略是否清晰,冷热分层、删除、归档是否能落地

这一层如果不先收稳,后面做再多压测都容易失真。因为很多性能问题并不是集群能力不足,而是索引先设计错了:

  • 小索引分片过多,导致集群元数据和调度开销被放大
  • 大索引只有少量分片,单分片成为热点
  • 动态字段过多,导致 mapping 膨胀和内存占用异常
  • 副本数量过高,写入成本被无意义放大

3. 写入层:别只测“能写入”,要测“持续写时会不会退化”

写入层最小验证不应该只是一条 bulk 成功,而应该包含下面几组动作:

  • 单条写入延迟
  • 批量写入吞吐
  • 长稳写入下的刷新与合并开销
  • 高峰写入下的拒绝和队列堆积
  • 写入期间副本同步和恢复影响

测试写入时更需要盯的不是单次吞吐,而是下面几组关系:

  • 写入量提升时,吞吐是否线性增长
  • 吞吐不再增长时,线程池、磁盘、JVM 哪一层先出现拐点
  • 写入持续 30 分钟、1 小时、2 小时后,延迟是否开始恶化
  • 批量大小变化后,写入效率和资源消耗如何变化

4. 查询层:不要只做一条 DSL,应该按查询模型分组验证

Elasticsearch 查询测试最怕只挑一条“代表性查询”。
更能反映真实现场的做法,是按查询模型分组:

  • 精确查询
  • 范围查询
  • 排序分页
  • 聚合统计
  • 多字段组合过滤
  • 模糊查询和高亮

每一类查询都至少要回答:

  • 平均耗时和尾延迟是多少
  • 并发升高后是 CPU、缓存还是磁盘先抬头
  • 是否有某些 DSL 在数据量扩大后明显失控
  • 是否存在命中率低、缓存无效、扫描范围过大的查询

5. 运维层:扩容、恢复、节点异常必须进测试范围

Elasticsearch 测试理解成性能压测,这不够。
ES 这类中间件真正的风险,经常出现在运维动作里:

  • 节点重启
  • 节点扩容
  • 节点故障摘除
  • 分片迁移
  • 磁盘逼近高水位
  • 快照与恢复

如果这些动作从来没测过,线上第一次遇到时,最容易出现下面的问题:

  • 集群能恢复,但恢复时间过长,业务窗口顶不住
  • 分片迁移期间查询明显抖动
  • 扩容后热点仍然没消失,因为索引和路由策略没调整
  • 水位触发后索引进入只读,业务侧才第一次发现

三、监控口径怎么定,才能真正解释集群状态

Elasticsearch 监控最怕的不是没有图,而是图很多但解释不了问题。
更实用的方式,是把监控口径拆成四类:

  • 可用性口径
  • 性能口径
  • 容量口径
  • 恢复口径

1. 可用性口径:回答“集群是不是还能提供服务”

至少要看:

  • 集群健康状态
  • 节点在线数量
  • 主分片和副本分片状态
  • 未分配分片数
  • pending tasks 数量
  • 线程池拒绝次数

这组指标的价值在于快速回答:

  • 集群是否已进入异常状态
  • 当前是否在恢复、迁移或堆积
  • 问题是局部节点,还是已经影响整个集群

2. 性能口径:回答“为什么开始变慢”

性能侧至少应该盯:

  • 写入吞吐、写入延迟、bulk 耗时
  • 查询 QPS、查询耗时、P95、P99
  • refresh 耗时
  • merge 耗时
  • search 线程池和 write 线程池队列长度
  • JVM heap 使用率、GC 次数和停顿

这里最重要的不是看单点峰值,而是看时间关系:

  • 查询慢之前,是不是先发生了 merge 抖动
  • 写入降速之前,线程池是不是已经堆积
  • heap 抬高之前,字段或聚合模型是否刚变化

3. 容量口径:回答“还能不能继续承载”

容量口径至少包括:

  • 磁盘使用率和水位阈值
  • 分片总数、单节点分片数
  • 索引体量增长趋势
  • 文档数增长趋势
  • segment 数量
  • fielddata、query cache、request cache 占用

这组指标的目标不是做展示,而是支撑决策:

  • 什么时候该扩容
  • 什么时候该缩减分片
  • 什么时候该做冷热分层
  • 什么时候该回收旧索引

4. 恢复口径:回答“异常后多久能回稳”

这是 容易漏掉的一组。
恢复相关至少应该长期观察:

  • shard relocation 数量
  • recovery 耗时
  • 节点重启后恢复窗口
  • snapshot 成功率和耗时
  • 故障后写入与查询恢复到正常口径的时间

如果没有这组监控,现场通常只能看到“集群已经恢复”,但看不到下面这些更关键的问题:

  • 恢复用了多久
  • 恢复期间是不是已经拖慢业务
  • 恢复完成后是否还有尾部问题没收敛

四、最小执行骨架应该怎么搭,避免一上来就全量压

更适合 Elasticsearch 集群的最小执行骨架,通常是下面五步。

1. 准备阶段

准备阶段至少要固定:

  • 节点角色和数量
  • 索引模板和映射版本
  • 测试数据规模
  • 典型写入模型
  • 典型查询模型
  • 监控面板和记录表

建议提前准备一张最小记录表:

阶段 写入模型 查询模型 数据量 分片/副本 目标指标 观察点
冒烟 单条写入 精确查询 10 万 3/1 功能正确 健康、分片、拒绝数
基线 bulk 写入 常用 DSL 100 万 3/1 平均耗时 heap、线程池、磁盘
升压 bulk 写入 聚合 + 排序 500 万 3/1 P95、拒绝率 merge、refresh、GC
长稳 混合流量 混合流量 持续增长 3/1 稳定性 水位、segment、pending tasks
故障 节点摘除/恢复 混合流量 持续增长 3/1 恢复时间 relocation、恢复耗时

2. 冒烟阶段

冒烟阶段不追求吞吐,重点确认:

  • 索引创建和模板生效是否正确
  • 写入和查询是否能打通
  • 节点与分片状态是否符合预期
  • 基础监控是否有数据

3. 基线阶段

基线阶段主要回答:

  • 当前数据模型下,集群正常吞吐是多少
  • 常用查询的平均耗时和尾延迟是多少
  • 哪些资源先开始被消耗

4. 升压与长稳阶段

这里重点不是“打到挂”,而是找拐点:

  • 从哪个并发或吞吐开始,延迟明显恶化
  • 写入和查询混合时,哪个线程池先堆积
  • 长稳运行时,segment、merge、GC 是否持续恶化

5. 故障与恢复阶段

这一阶段最好保留,不然测试结论通常不完整。
至少建议做:

  • 单节点重启
  • 单节点摘除
  • 磁盘逼近阈值时观察写入与查询
  • 恢复期间继续保持低量业务流量

五、监控面板和命令口径应该怎么搭

1. 基础命令口径

现场排查时,下面这组命令通常最常用:

1
2
3
4
5
6
7
8
curl -s http://127.0.0.1:9200/_cluster/health?pretty
curl -s http://127.0.0.1:9200/_cat/nodes?v
curl -s http://127.0.0.1:9200/_cat/shards?v
curl -s http://127.0.0.1:9200/_cat/allocation?v
curl -s http://127.0.0.1:9200/_cluster/pending_tasks?pretty
curl -s http://127.0.0.1:9200/_nodes/stats?pretty
curl -s http://127.0.0.1:9200/_cat/thread_pool?v
curl -s http://127.0.0.1:9200/_cat/indices?v

这组命令的价值,不是替代监控系统,而是在图表之外快速回答:

  • 当前是不是已经有未分配分片
  • 哪个节点磁盘或分片明显更重
  • 哪个线程池已经开始排队或拒绝
  • 是否存在 pending task 积压

2. 最小监控面板建议

更适合现场排查的面板通常至少有四张:

  • 集群总览盘:健康状态、节点数、未分配分片、pending tasks、磁盘水位
  • 写入盘:bulk 吞吐、写入耗时、write 队列、拒绝数、refresh 与 merge
  • 查询盘:查询 QPS、查询耗时、search 队列、cache 命中、热点索引
  • 恢复盘:recovery、relocation、节点重启窗口、快照与恢复耗时

3. 观察与判断顺序

更高效的判断顺序通常是:

  1. 先看集群有没有进入恢复或异常状态
  2. 再看写入还是查询先变差
  3. 再看线程池、磁盘、JVM、merge 谁先抬头
  4. 最后再下钻到索引模板、映射和 DSL

如果一开始就扎进某条查询或某个节点,往往容易把全局问题误判成局部问题。

六、常见坑

1. 只看集群颜色,不看分片与热点

green 只能说明主分片和副本分片都已分配,不代表分布合理。
真实问题里经常出现:

  • 一个节点承担了大部分热点分片
  • 分片数量太多,管理开销先把集群拖慢
  • 查询热点集中在少数索引或少数节点

2. 分片数靠经验拍,后面再补救

很多索引上线时直接按“感觉”设分片数,后面数据量增长后只能被动迁移和重建。
分片数一旦不合理,后续所有测试都会被扭曲。

3. 只压写入或只压查询,不压混合流量

很多真实业务不是纯写或纯查,而是:

  • 写入持续发生
  • 查询也持续发生
  • 后台聚合、分页、统计同时在跑

只做单一流量模型,很容易得到过于乐观的结论。

4. 忽略 refresh、merge 和恢复带来的抖动

写入延迟出现抖动时,最先被怀疑的通常是网络或节点不稳。
但很多时候真正的触发点是:

  • refresh 过于频繁
  • merge 放大
  • recovery 与 relocation 挤占资源

5. 只盯 JVM,不看磁盘水位和 segment

Elasticsearch 的问题不止发生在 heap。
磁盘水位、segment 数量、merge 压力和分片恢复,同样能在没有明显 OOM 的情况下先把集群拖慢。

6. 节点恢复完就当问题结束

节点恢复完成不代表业务已经恢复到原口径。
更应该继续观察:

  • 写入吞吐是否回到基线
  • 查询 P95 是否回到基线
  • pending tasks 是否清空
  • 是否还有热点节点和热点分片残留

七、真实案例:写入和查询都变慢,到底是节点不稳还是索引策略先出问题

场景

一个测试平台把执行结果、日志摘要和告警事件都写入 Elasticsearch
平时集群一直能用,但在某次回归峰值期间出现了明显问题:

  • bulk 写入开始变慢
  • 日志检索延迟明显升高
  • 聚合统计接口超时增加
  • 集群状态仍然是 green

排查起点通常会先落在节点资源上,怀疑是磁盘或 JVM 顶住了。

执行

现场按下面顺序收证:

  1. 看集群健康、节点列表、分片分布
  2. 看写入线程池、查询线程池、拒绝数和 pending tasks
  3. 对齐写入吞吐、查询耗时、refresh、merge、GC、磁盘水位时间窗
  4. 下钻到热点索引,检查模板、分片数和字段映射
  5. 对照最近一次索引模板变更和业务查询变更

现象

现场看到的关键现象是:

  • 集群整体仍然 green
  • 没有节点离线,也没有明显 master 抖动
  • write 线程池开始排队,search 线程池偶尔抬高
  • merge 时间在峰值窗口明显上升
  • 磁盘水位虽然没过阈值,但某两个节点增长明显更快
  • 热点索引的分片数偏少,且一个高基数字段被用于聚合和排序

排查

继续下钻后,问题逐步收敛:

  • 这批回归新增了大量日志事件字段,mapping 膨胀速度超出预期
  • 热点索引分片数偏少,导致写入和查询都集中打到少量分片
  • 聚合和排序都围绕同一高基数字段展开,search 压力进一步集中
  • merge 在高写入窗口持续放大,磁盘和线程池被进一步拖慢

这说明真正的问题不是“集群忽然扛不住”,而是:

  • 索引模板和字段设计先把热点做出来了
  • 回归流量只是把这个问题提前放大

修复

最终修复动作分成四步:

  1. 调整索引模板,限制动态字段扩张,收紧不必要的聚合字段
  2. 重建热点索引,重新规划分片数和副本数
  3. 拆分高成本聚合查询,避免与高峰写入窗口完全重叠
  4. 在监控里新增热点索引分片负载、merge 耗时、search/write 队列和字段增长趋势

修复后再次复测,结果出现了明显变化:

  • bulk 写入吞吐恢复稳定
  • 聚合查询 P95 明显下降
  • merge 抖动窗口缩短
  • 同样的回归峰值下,线程池不再持续堆积

这个案例最关键的教训不是“ES 需要扩容”,而是:

如果索引策略、字段策略和查询模型没有先收稳,单纯扩容只能延后问题,不会真正消除问题。

八、结论

Elasticsearch 集群测试真正要解决的,不是证明“它能工作”,而是回答下面几个更具体的问题:

  • 这个集群在当前索引和查询模型下是否稳定
  • 写入、查询、恢复、扩容时哪个环节最先成为限制
  • 当前监控口径能不能在问题发生前给出趋势信号
  • 故障发生后,能不能快速分清是集群问题、索引问题还是查询问题

更实用的做法通常不是一上来就追求复杂压测,而是先把下面几件事收稳:

  • 验证分层:集群、索引、写入、查询、运维
  • 监控口径:可用性、性能、容量、恢复
  • 执行骨架:冒烟、基线、升压、长稳、故障恢复
  • 证据顺序:健康状态、分片分布、线程池、磁盘/JVM、模板与 DSL

只有这几条链路一起收起来,Elasticsearch 测试结论才不会停留在“能用”或“变慢了”,而是能真正支撑发布验证、容量判断和故障定位。