ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Elasticsearch 8.x集群监控与运维实战:从指标选型到告警配置

Elasticsearch 8.x集群监控与运维实战:从指标选型到告警配置 监控和运维这套东西我在 Elasticsearch 集群上折腾了不短的时间最深的体会是它不是可有可无的收尾工作而是让集群长期稳定运行的地基。Elasticsearch 8.x 推出来之后安全认证默认开启、部分监控能力并入基础版很多团队的运维习惯却还停留在“装好、索引建起来、能查就行”的阶段等磁盘水位打满或者堆内存跑飞才开始慌慌张张翻日志。这篇文章我把基于 Elasticsearch 8.x 的监控与运维经验完整梳理一遍重点覆盖指标怎么选、监控工具链怎么搭、日志和告警怎么用、日常运维动作怎么配合以及真实故障的排查链路。想给现网集群搭一套能落地的监控体系或者已经在用 ES 8.x、想补齐运维短板的工程师都可以直接参考。内容都是可以直接照做的没有太多理论空谈。1. 先把监控指标体系摆平哪些指标值得守着哪些不用看一上来就谈工具链是错的。先想清楚一个问题ES 集群到底哪些指标不盯着会出事我见过不少团队把 Grafana 面板做得花里胡哨几十个图真正磁盘打满的时候反而是靠业务方投诉才知道。归根结底监控的不是数据是风险。指标选错了工具再贵也没用。1.1 集群健康三色灯只能告诉你“能不能查”不能告诉你“好不好”很多新运维上手 ES第一件事就是每分钟跑一次curl localhost:9200/_cluster/health看到 green 就放心。这个动作没问题但容易产生一种错误的安全感。_cluster/health返回的绿黄红三色实际上只描述分片状态green所有主分片和副本分片都已就位yellow主分片正常至少一个副本分片处于 unassigned 状态red至少一个主分片未分配这部分数据无法读取或写入问题在于一个 green 集群可能正在被写入拒绝折磨。bulk 队列打满、线程池 active 满、JVM 老年代频繁 Full GC这些都不会改变颜色。一个 yellow 集群也可能是安全的比如单节点测试环境根本没地方放副本yellow 挂一天业务也没受影响。所以我把集群健康当作“底线指标”而不是“核心指标”。它负责提醒你数据副本是否完整但性能水位要靠下面的指标来扛。建议抓/cluster/health做基础巡检同时把监控重点放在分片分配异常、堆内存和磁盘上。1.2 第一梯队指标堆内存、GC、线程池与磁盘水位我建议任何 ES 集群最先接上的监控至少包含下面四类堆内存使用率ES 的 JVM 堆不是用来看剩余量的而是用来控制 GC 压力和缓存容量的。8.x 默认使用 G1GC堆上限按官方建议不要超过 30GB常见配置是 16GB 到 30GB。监控上主要看node_stats.jvm.mem.heap_used_percent我一般设两个阈值85% 告警92% 严重。这里要注意堆内存使用率有“水位浮动”是正常的索引写入、聚合计算、分片恢复都会让堆短暂爬升。真正危险的是长时间维持在 85% 以上不回落或者老年代 GC 频率肉眼可见地加快。GC 次数与耗时_nodes/stats/jvm里能看到 young GC 和 old GC 的次数、耗时。G1GC 的特点是 young GC 很频繁old GC 偶尔出现。如果 old GC 从每小时几次变成每几分钟一次或者单次停顿超过 1 秒基本可以断定堆里有大量长生命周期对象。最常见的元凶就是太多的 segment 和 fielddata 缓存。线程池拒绝量ES 每个节点默认按功能划分线程池search、bulk、write、get 各管各的。队列满了之后新请求直接拒绝客户端会收到es_rejected_execution_exception或者429 Too Many Requests。这是一个极其关键的业务指标因为它直接代表“集群已经处理不过来了”。建议定时抓_cat/thread_pool?v或_nodes/stats/thread_pool重点关注bulk、search、write三个池子被拒绝的数量。如果拒绝量持续大于 0说明写入或查询的速率已经超过集群处理能力这时候加机器不如先限速。磁盘剩余空间ES 的磁盘水位机制是运维事故的高发区。默认配置下磁盘使用率达到 85%low watermark时该节点不再分配新分片达到 90%high watermark时集群会尝试把分片迁到其他节点达到 95%flood stage时所有索引强制进入只读状态写入直接失败。很多团队第一次踩坑都是栽在最后一档凌晨磁盘打满第二天业务反馈写不进去了然后发现索引被自动加了read_only_allow_delete块。我给的阈值建议是分级告警指标采集方式建议阈值对应问题堆内存使用率_nodes/stats或 Metricbeat85% 告警92% 严重段数量过多、缓存膨胀old GC 频率_nodes/stats/jvm持续升高或单次超过 1s堆压力、需要重启或调优线程池拒绝数_cat/thread_pool持续大于 0写入/查询超负荷磁盘剩余率_nodes/stats/fs剩余不足 15% 告警分片分配受限、只读风险磁盘这块我个人建议不要死等官方 85% 的默认值。如果你的节点上有大量 ES 之外的占用比如日志、系统文件最好把监控阈值提前到剩余 10% 甚至 15% 就告警给运维留出清理和扩容的时间。1.3 第二梯队指标分片、段与缓存命中率第一梯队保命第二梯队保证你过得舒服。这层指标不一定需要实时告警但排查问题时非常好用。未分配分片数cluster_stats.indices.unassigned_shards红色集群的直接来源。unassigned 数量不为 0 时要结合_cluster/allocation/explain看具体原因。relocating_shards正常情况下这个数字接近 0。它长期不为 0 说明集群一直在做分片迁移要么是新增节点后的 rebalance要么是磁盘水位线触发了自动迁移也可能是某节点反复掉线触发 recovery。segment 数量与内存占用查询_cat/segments?vsmemory:desc看每个索引的 segment 占用堆内存情况。segment 是 Lucene 的基本存储单元它的数量太多会导致查询变慢同时每个 segment 的元数据也会占堆。经验法则是单个分片的 segment 内存超过几百 MB 就要警惕了。查询缓存命中率_nodes/stats/indices/query_cache和request_cache。filter 上下文相同的查询可以命中 query cache聚合和排序可以走 request cache。命中率低意味着每次查询都在做真实的磁盘和计算工作这是优化查询的重要入口。2. 官方 Stack Monitoring 与 Prometheus Grafana两套监控链路怎么选指标想清楚了下一步是选采集和展示方式。Elasticsearch 8.x 时代基本两条路线一条是官方栈内自带的 Stack Monitoring走 Metricbeat 采集数据另一条是 Prometheus 生态靠 elasticsearch_exporter 或原生/prometheus/metrics端点抓指标再用 Grafana 展示和告警。两条路我都跑过各有各的适用场景。2.1 Metricbeat Stack Monitoring零开发数据链路最短Metricbeat 是 Elastic 官方轻量采集器。它直接调用 ES 的_cluster/health、_nodes/stats、_cluster/stats、索引统计等 API把监控数据写到一个监控集群或同一个集群的.monitoring-*索引里然后 Kibana 的 Stack Monitoring 页面直接可视化成节点列表、分片样式、索引状态、堆内存曲线等。这套方案最大的优点是不需要开发装完就有完整的仪表盘。步骤大概是安装 Metricbeat版本和 ES 主版本保持一致。修改modules.d/elasticsearch.yml核心配置如下- module: elasticsearch metricsets: - node - node_stats - cluster_stats - index - index_recovery - shard period: 30s hosts: [https://es-node1:9200, https://es-node2:9200] username: metricbeat_agent password: your-password ssl.enabled: true ssl.verification_mode: none在 Kibana 里创建监控专用账号角色用内置的remote_monitoring_agent或monitoring_user。不要图省事把超级用户elastic的密码直接填进 Metricbeat 配置文件安全审计会在某个时刻找你麻烦。启动 Metricbeat然后到 Kibana 左侧菜单的 Stack Monitoring 页面看数据是否进来。需要注意Stack Monitoring 默认生成的.monitoring-*索引有自己的生命周期管理但不代表你完全不用管。小集群上这些监控索引长期积累也会占用磁盘建议在 Kibana 或 ILM 中把保留周期调整到 7 天左右。这也是我接监控后第一批被提醒“磁盘又被监控吃掉了”的地方之一。2.2 elasticsearch_exporter Prometheus Grafana告警生态更成熟如果你的公司已经有 Prometheus Grafana 这套基础设施我建议直接走这套。它的优势在于告警规则管理成熟Grafana 社区拿来即用的 ES 看板很多而且监控数据和业务其他指标的告警可以归到一个 Alertmanager 里统一通知。我用的是 prometheus-community/elasticsearch_exporter。部署方式很简单一个容器或一个二进制进程指向 ES 的地址即可docker run -d --name es-exporter -p 9114:9114 \ prometheuscommunity/elasticsearch-exporter \ --es.uri https://es-node:9200 \ --es.username prom_agent \ --es.password your-password然后在 Prometheus 的scrape_configs里加上这个 exporter 的目标scrape_configs: - job_name: elasticsearch static_configs: - targets: [es-exporter:9114]exporter 会暴露一堆elasticsearch_*前缀的指标集群健康状态、JVM 堆内存、磁盘空间、GC 耗时、搜索和索引速率都有覆盖常规运维绰绰有余。Grafana 社区搜 “elasticsearch exporter” 或 “Elasticsearch Overview”导入面板后按数据源调整指标名即可。另外一个选项是直接使用 ES 8.x 自带的/_prometheus/metrics端点。确认elasticsearch.yml里开启了xpack.monitoring.collection.enabled: true然后 Prometheus 就能直接抓这个地址省掉一个 exporter 进程。不过我实际用下来原生端点指标覆盖面比 exporter 少一些主要适合轻量监控。如果你需要的是更细的分片级、索引级指标还是上 exporter 更省心。两个方案可以做个简单对比维度Metricbeat Stack Monitoringelasticsearch_exporter Prometheus Grafana安装成本中需配置 Metricbeat 和 Kibana低一个 exporter 容器即可仪表盘官方完整页面零开发社区看板需要微调指标名告警能力依赖 ElastAlert 或额外配置Alertmanager 原生规则能力更强指标丰富度分片级、索引级都覆盖覆盖面广深度稍弱适用场景Elastic 全家桶用户已有 Prometheus 体系的公司2.3 8.x 安全认证后的监控接入配置别在这里踩坑8.x 和 7.x 最大的运维差异之一是安全默认开启。很多监控组件默认用 http 去连 9200直接连不上还有的直接填elastic超级用户密码虽然也能跑但权限太大不是该有的做法。我的推荐是给每种监控组件单独建账号只授最小权限。Metricbeat 用remote_monitoring_agentelasticsearch_exporter 可以给它配一个只读角色。创建用户的 API 很简单curl -k -u elastic:your-pass \ -X POST https://es-node:9200/_security/user/monitoring_agent \ -H Content-Type: application/json \ -d {password: strong-password, roles: [remote_monitoring_agent]}如果走的是https注意处理好证书。自签名证书场景下Metricbeat 的ssl.verification_mode: none和 exporter 的--ssl.skip-verify都可以暂时跳过校验但内网环境下建议还是把 CA 证书挂上避免中间人风险。我在测试环境里踩过最蠢的坑Metricbeat 配置了verification_mode: certificate但证书的 hostname 和实际节点 IP 对不上采集一直失败结果花了一下午查出来是证书 SAN 字段没加 IP。所以要么一开始就写verification_mode: none要么就把证书做规范。监控账号建好后要检查是否真的能拿到数据。可以手动请求 exporter 暴露的 metrics 接口或者直接 curl 一下 ES 原生端点确认输出里包含你想要的指标。这一步不贵能省后面排查故障时“是不是监控坏了”的猜疑链。3. 日志、慢查询与告警故障从发生到发现的最短路径指标解决的是“现在出了问题”日志解决的是“为什么出问题”。有些故障只靠曲线是定位不了的比如某个查询突然变慢你从 Grafana 上能看到 TPS 下降但看不到是哪个查询、哪条 DSL、命中哪个索引。这时候必须翻慢日志。3.1 日志文件不止 elasticsearch.log慢日志和 GC 日志才是查问题的钥匙ES 8.x 默认日志目录在$ES_HOME/logs或/var/log/elasticsearch常见的日志文件有这几个日志文件内容使用场景elasticsearch.log主运行日志节点启动、分片分配、异常堆栈都在这排查节点下线、分片失败、权限错误elasticsearch_deprecation.log过期 API 和功能弃用告警升级前检查兼容性elasticsearch_index_search_slowlog.log查询慢日志定位哪些查询超过指定耗时elasticsearch_index_indexing_slowlog.log写入慢日志定位写入卡顿gc.logJVM GC 日志分析停顿、GC 频率、堆分配情况主日志的优先级我觉得反而不如慢日志和 GC 日志。主日志大多数时间是几十行 INFO一遇到大量分片恢复或节点重启就疯狂输出。真正遇到问题的时候主日志里的 ERROR 堆栈通常只是现象原因要结合 GC 日志和慢日志一起看。比如节点反复脱线主日志只写着 “master not discovered yet”但 gc.log 里可能记录了多次超过 5 秒的 Full GC 停顿这才是根因。3.2 慢日志配置五分钟内抓到拖慢业务的查询慢日志是索引层面的配置。它不记录全部查询只记录执行时间超过你设定阈值的查询。以某个业务索引为例curl -X PUT https://es-node:9200/logs-2025-01/_settings \ -H Content-Type: application/json \ -d { index.search.slowlog.threshold.query.warn : 2s, index.search.slowlog.threshold.query.info : 500ms, index.search.slowlog.threshold.fetch.warn : 1s, index.search.slowlog.threshold.fetch.info : 500ms, index.indexing.slowlog.threshold.index.info : 500ms }query阶段和fetch阶段要分开看。query 慢通常是倒排索引或过滤器设计问题fetch 慢往往是返回字段太多或_source 太大。warn、info、debug、trace四个级别对应不同的阈值日志文件也不同。我建议第一次配置时只开info和warn不要直接开trace否则写入频繁的索引会把慢日志文件写爆。慢日志会用 JSON 格式记录完整的查询体耗时、索引名、分片号、节点名都有。拿到之后可以复制 DSL 到 Kibana 的 Dev Tools 里单独跑一遍用 Profile API 看每个子查询的耗时分布。这里要注意慢日志记录的是超过阈值的那批请求不代表所有请求都慢。如果你发现慢日志量巨大但业务感知不强先别急着改一堆东西看看是不是阈值设置得过低把正常范围内的慢请求也给记录下来了。3.3 告警规则Alertmanager 与 ElastAlert 两条路线告警是整个监控体系的最后一公里。没告警的监控只是“事后报表”有告警才能叫“事前预警”。如果用的是 Prometheus 方案Alertmanager 是首选。我常用的几条 ES 告警规则如下groups: - name: elasticsearch_alerts rules: - alert: ESClusterRed expr: elasticsearch_cluster_health_status 2 for: 2m labels: severity: critical annotations: summary: ES 集群进入 RED 状态 - alert: ESHeapUsageHigh expr: elasticsearch_jvm_memory_used_bytes{areaheap} / elasticsearch_jvm_memory_max_bytes{areaheap} 0.85 for: 10m labels: severity: warning annotations: summary: ES 堆内存超过 85% - alert: ESDiskAlmostFull expr: elasticsearch_filesystem_free_bytes / elasticsearch_filesystem_size_bytes 0.1 for: 5m labels: severity: critical annotations: summary: ES 节点磁盘剩余低于 10%如果用的是 Metricbeat Stack Monitoring 但没有搭 Prometheus可以用 ElastAlert 2 来跑针对.monitoring-*索引或业务索引的告警。它的原理是周期性地把 query DSL 放到 ES 上跑命中了就触发告警发送到钉钉、企业微信、邮件或 webhook。比较适合告警逻辑复杂、需要做时间窗口去重的场景。我的经验是告警规则宁少勿滥。第一版先管四件事集群 RED、堆内存高、磁盘快满、慢查询突增。等跑一段时间把“每次出事都靠它提醒”的规则留下来把“半夜疯狂刷屏但没人处理”的规则删掉。告警疲劳是真实存在的一天几十条没人理的告警不如一条命中要害的告警有价值。4. 监控看到问题之后日常运维动作要跟着动监控很重要但它只是眼镜不是手。看完指标你总得做事。这里我把几个频率最高的运维场景拿出来说说每个都对应监控会暴露出来的具体信号。4.1 滚动重启的正确顺序先停迁移再逐台重启升级、换配置、调 JVM 参数都需要重启节点。对于多节点集群我推荐滚动重启操作的顺序有讲究。第一步先把分片自动分配关掉避免节点重启期间集群疯狂做分片迁移导致网络和 IO 被打爆curl -X PUT https://es-node:9200/_cluster/settings \ -H Content-Type: application/json \ -d { persistent: { cluster.routing.allocation.enable: none } }第二步对要重启的节点执行一次 flush把内存中的索引数据尽量落盘curl -X POST https://es-node:9200/_flush第三步逐台重启节点。每台重启后要等它重新加入集群并且分片恢复完成集群状态回到 green再继续下一台。千万不要一键把所有节点全部重启那等于把集群主动停了一次。所有节点都完成后再重新开启分片分配curl -X PUT https://es-node:9200/_cluster/settings \ -H Content-Type: application/json \ -d { persistent: { cluster.routing.allocation.enable: null } }关掉分配这步不是必须的但绝大多数场景下建议做。它相当于告诉集群“我要做维护了你先别折腾分片”能显著缩短节点重启后的恢复时间。4.2 磁盘水位线与分片分配控制磁盘监控告警触发后第一步不是马上加磁盘而是先看当前水位线配置是否合理。默认 85%、90%、95% 三条线适合多数场景但如果某台机器磁盘特别大或特别小建议按实际情况调整curl -X PUT https://es-node:9200/_cluster/settings \ -H Content-Type: application/json \ -d { persistent: { cluster.routing.allocation.disk.watermark.low: 80%, cluster.routing.allocation.disk.watermark.high: 87%, cluster.routing.allocation.disk.watermark.flood_stage: 92% } }如果已经触发了 flood stageES 会自动给索引加上read_only_allow_delete块。这时即使你删掉了部分数据索引仍然不能写入必须手动解除curl -X PUT https://es-node:9200/your-index/_settings \ -H Content-Type: application/json \ -d { index.blocks.read_only_allow_delete: null }这个细节我在现场救过很多次急。不少人删完数据发现写入还是失败以为要等集群自己恢复其实只是没解开 index block。磁盘水位异常还经常伴随分片分配失败的告警比如某个节点磁盘高水位导致副本无法分配。排查方法用_cluster/allocation/explain它会明确告诉你当前阻塞的原因是“磁盘水位过高”还是“分片数限制”还是“节点不在线”。这比你自己猜要快得多。4.3 ILM、forcemerge 与快照数据面的运维三件套监控指标里如果长期能看到 segment 内存高企、查询越来越慢多半是索引维护动作没跟上。ILM索引生命周期管理是最有效的手段它把索引按照生命周期阶段自动管理热阶段写入、温阶段只读、冷阶段压缩、删除阶段清理。一个常见的 ILM policy 大致这个样子{ policy: { phases: { hot: { actions: { rollover: { max_primary_shard_size: 50gb } } }, warm: { actions: { forcemerge: { max_num_segments: 1 } } }, delete: { actions: { delete: {} } } } } }然后把这个 policy 绑定到索引模板上新建索引会自动套用。forcemerge到单个 segment 能显著减少 segment 数量和堆内存占用但它要求索引只读。所以操作上要确保 ILM 已经先把索引置为只读或者你自己确认没有客户端在写它。快照备份属于不放监控里也要定期做的事。ES 8.x 的快照和恢复体系已经非常成熟创建文件仓库后定时打快照就行curl -X PUT https://es-node:9200/_snapshot/my_repository \ -H Content-Type: application/json \ -d { type: fs, settings: { location: /mnt/elastic-backups } }然后每天固定时间执行快照。很多人忽视的一点是没有快照的监控体系等于只看体温不开药方等于是等崩溃后才后悔。5. 三个高频故障拿监控数据倒着推前面讲的是工具和步骤。这一节作用相当于“实战演练”我把现网最常遇到的三个问题展开说说重点不是给结论而是展示怎么从监控数据一步步倒推出原因。5.1 集群变黄第一反应不是重启而是看分配场景某天监控告警说集群状态从 green 变成了 yellow持续十几分钟。很多人的第一反应是重启节点这是最容易被带偏的操作。正确排查路径应该是先看哪些索引的副本没分配curl -s https://es-node:9200/_cat/indices?vsstatus:desc用_cluster/allocation/explain问集群为什么不分配curl -X GET https://es-node:9200/_cluster/allocation/explain?pretty这个 API 会直接给出阻塞原因。我实际遇到的 mostly 是三类磁盘水位过高节点不愿意再接收分片副本数大于节点数比如单节点集群配了副本数为 1没地方放副本索引或分片的 total_shards_per_node 限制卡住分配对症下药就行。单节点测试环境最省事的办法是把副本数改成 0 或 1集群回到 green如果是磁盘问题清理数据或扩容后解除只读块和水位限制。这里重点提醒集群 yellow 不可怕盲目重启才是最坏的操作。重启会让 master 重新选举和分片恢复期间可能触发大量 IO进一步延长问题窗口。5.2 堆内存下不来segment 和 fielddata 往往真凶场景集群运行了几个月监控曲线显示堆内存从 60% 缓慢爬升到 90%重启后降到 50%过两周又爬回来。这种情况多半不是程序 bug而是数据留在堆里的东西越来越多。排查顺序看_nodes/stats/jvm里 old GC 的趋势线确认是不是在加速。看 segment 内存占用排第一名的索引基本就是嫌疑curl -s https://es-node:9200/_cat/segments?vsmemory:desc对只读索引执行 forcemergecurl -X POST https://es-node:9200/your-index/_forcemerge?max_num_segments1如果 fielddata 太大检查是否有大数据量的 terms 聚合直接作用在 high-cardinality 字段上。这类字段的 fielddata 会大量占用堆内存而且很难自动释放。我在某个监控系统集群上遇到过堆内存 92% 持续了一周排查后发现是一个上亿条文档的索引segment 内存占了 60% 的堆。做了 ILM 加 forcemerge 后堆稳定在 70% 以下查询延迟还降了一半。重启只是缓兵之计把 segment 和 fielddata 这些长期驻留堆的东西清理掉才是根除。5.3 查询延迟突增先看 OS 缓存再分析慢日志场景业务反馈搜索接口从平均 30ms 涨到 300msGrafana 上 CPU 和堆内存都不高看起来一切正常。这种情况十有八九是命中不了缓存或者磁盘 IO 变慢。我的排查顺序是先看慢日志确认是哪类查询变慢拿到具体 DSL。看系统层面的 cache 状况。ES 官方建议堆外内存尽量留给 OS page cache如果机器上还跑了其他大内存应用page cache 被挤掉查询需要反复从磁盘读延迟自然就上来了。这个用free -h或者操作系统监控能看到实际可用缓存远小于物理内存。用 Profile API 分析 DSL 的子查询耗时看是不是 filter 没有走缓存、聚合 size 拉得过大、或者_source返回来太多无用字段。优化手段不复杂高重复性查询尽量做成 filter context利用 query cache排序和聚合用 docvalue_fields大数据量导出场景不要走普通 search考虑_search/scroll或 PIT 机制。多数查询变慢问题在慢日志和 Profile API 结合下都能定位到具体原因而不是凭感觉调一堆参数。最后说两句个人经验监控体系搭建不是一步到位的事更不是面板越多越好。我接手第一套 ES 8.x 集群时只做了三件事磁盘剩余空间和堆内存的阈值告警、集群健康状态的定期巡检、慢日志接入。坚持一个月后线上没有再出现磁盘打满的事故反而是慢日志帮我发现了两个之前从未意识到的低效查询。对刚接触 ES 8.x 运维的人我的建议是先把磁盘、堆内存、集群健康、慢日志这四件事管住再逐步补上 GC 日志、exporter、告警规则。先把基础盘稳了后面再加水位线、ILM、快照这些进阶功能。运维的主动权不是靠一套复杂的工具链拿到的而是靠最基础的那几条告警和对日志的敏感度拿到的。
返回列表