主题
Nacos 监控指标与告警
一句话:Nacos 的监控要同时盯三条链:连接、实例、配置;任何一条先变坏,都会先在业务侧以「实例没了」或「配置没生效」出现,而不是以 Nacos 进程退出出现。
适用版本:Nacos 3.2.4;涉及 2.5.4 的行为差异单独标注。3.3 起客户端指标改用 Micrometer,名称和单位与 3.2 及更早版本不同;指标名、端点、默认值以对应版本文档和节点实际指标输出为准,数值只是起点,按自己的基线校准。
相关:05-高可用与容量规划、07-Nacos生产踩坑、04-集群与一致性。
为什么需要
Nacos 不在业务数据面,故障不会直接报「注册中心挂了」。它先表现为调用方拿不到实例、配置读到旧值、实例列表不刷新;等业务开始重试,Nacos 的负载已经被放大一轮。只看进程存活和 CPU 不够:进程还在,也可能已经没有 quorum、推送积压、直接内存见底。
05 讲接入方式、容量乘数和全挂行为;08 只讲盯哪些指标、什么先兆、告警与处置顺序,不重复容量测算。监控要回答四个问题:连接还在不在、实例名单是否可信、配置有没有推到、MySQL 是否拖住了前三条链。
核心机制
指标分层
表中的 serviceCount、publish 等是 nacos_monitor 的 name 标签值,不是独立指标名;查询要写成 nacos_monitor{module="naming",name="serviceCount"} 这类完整形式。
| 层 | 指标/来源 | 反映什么 | 恶化先兆 |
|---|---|---|---|
| 客户端面 | 3.3+:nacos_client_request_seconds_*、nacos_client_naming_request_failed_total、nacos_monitor{module="naming",name="serviceInfoMapSize"}、nacos_monitor{module="config",name="listenConfigCount"};3.2 及更早为旧名 nacos_client_request_*;快照时间看 ~/nacos 文件 mtime,重连看 remote.log,首次调用延迟用 APM/自建 histogram | 客户端看到的服务端、订阅与本地视图 | 首次调用超时、缓存计数异常、失败计数先涨 |
| 连接面(服务端) | nacos_monitor{module="core",name="longConnection"};与 ops API 的 clientCount/connectionBasedClientCount 及按 IP/clientId 前缀聚合的 SDK 客户端数对照,并看 grpc_server_executor 的 active/queue | 长连接规模与线程池压力 | 连接数与客户端数不匹配、队列堆积、重连后连接数锯齿 |
| 服务端进程 | jvm_memory_used_bytes/jvm_memory_max_bytes、jvm_gc_pause_seconds、jvm_threads_daemon(总线程数看 jvm_threads_live_threads,若暴露)、system_cpu_usage、system_load_average_1m;直接内存看 NMT/BufferPool,fd 看 process_files_open_files 或 lsof//proc;磁盘用 node_exporter | 进程还有多少余量 | GC 停顿接近心跳窗口、直接内存或 fd 见底 |
| 命名服务 | serviceCount、ipCount、subscriberCount、totalPush、failedPush、emptyPush、avgPushCost、maxPushCost、pushPendingTaskCount、leaderStatus;nacos_naming_subscriber/nacos_naming_publisher;客户端/实例/订阅计数用 /nacos/v3/admin/ns/ops/metrics?onlyStatus=false;Raft 摘要看 nacos_monitor_summary | 名单、推送和集群同步 | ipCount 骤降、failedPush/待推送涨、节点计数分叉、leader 变化 |
| 配置服务 | publish、getConfig、configCount、notifyTask、notifyClientTask、dumpTask、nacos_config_subscriber、nacos_timer{module="config"} 的 writeConfigRt/notifyRt/dumpRt、nacos_exception{module="config"}、config_change_count | 发布、通知、dump | 通知/dump 堆积、写与通知耗时升、异常涨、灰度版本或历史表膨胀 |
| 依赖 | MySQL Threads_connected/Threads_running、连接池等待(若暴露)、慢查询 digest、Seconds_Behind_Source、磁盘;config_info/his_config_info/config_info_gray 行数与体积 | 配置真相与启动 dump | 连接使用率高、慢查询增、主从延迟、磁盘水位、历史表增长 |
| 业务面 | 应用侧「无可用实例」错误率、注册后首次可调用延迟、配置发布到生效时延(APM/自建指标;Nacos 不直接提供) | 用户是否已经受影响 | 错误率先于 Nacos 指标变红,生效时延 p99 拉长 |
连接建立/断开速率与重连次数没有独立的稳定计数:服务端用 longConnection 的变化沿估算,客户端用 remote.log 的重连记录;grpc_server_requests 只能辅助看请求是否恢复,不是连接计数。不要给它们编一个不存在的指标名。健康/不健康实例数、心跳超时/摘除数、Distro 同步延迟或数据版本差也都没有官方稳定的单一指标名:用 ops API、按服务查询、逐节点 serviceCount/ipCount 对照和 naming-server.log 判断;持久实例的 Raft leader 与 apply 落后优先看 nacos_monitor_summary 的实际 label,查不到就写「以实际暴露为准」。配置侧没有官方单列的 failedPush,也没有覆盖常规 ConfigService 的稳定客户端拉取失败指标;用 notifyTask/dumpTask 堆积、nacos_exception{module="config"}、客户端 config.log 和自建埋点判断,不要套用命名服务的指标名。
指标怎么暴露
服务端指标走 Spring Boot Actuator,默认配置里是注释状态;在 conf/application.properties 打开 management.endpoints.web.exposure.include=prometheus,重启后访问 http://{host}:8848/nacos/actuator/prometheus。/nacos 来自 nacos.server.contextPath;改过上下文路径或 management port 就以实际为准。2.x(含 2.5.4)控制台在 8848/nacos,3.x 控制台独立在 8080;控制台能打开不代表指标在 8080,服务端指标仍以 server 端口和实际 /actuator/prometheus 为准。2.x 与 3.x 的 Actuator 暴露方式和路径也要按版本核实,不要照搬 8080 或 /metrics。
3.x 健康检查用 /nacos/v3/admin/core/state、/liveness、/readiness;独立控制台是 /v3/console/health/liveness|readiness。Nacos 3.3 起客户端指标通过 Micrometer 导出,enableClientMetrics 默认 true,但只有注册了 MeterRegistry 才会真正上报;3.3 的请求 timer 默认只覆盖 naming HTTP,常规 ConfigService 不会产生同名 config 序列。3.2 及更早的客户端指标名和单位不同,升级时先核对 dashboard。Actuator 只放内网,不要暴露公网。
雪崩链
回路在 C → D → E → F → G → C:连接断开不是一次性事件,实例被摘除后流量集中,剩余实例过载又制造更多心跳超时。处置要先切断回路:修 LB 空闲超时、放通 9848、给客户端重连加退避和抖动;直接重启 Nacos 会让所有客户端同时重连,把雪崩推得更高。
另外三条链用文字记住:MySQL 慢查询或连接池耗尽会让配置写入、dump 和通知变慢,客户端长时间读旧配置,严重时新实例无法启动;Distro/Raft 同步落后或推送失败会让客户端名单过期,调用打到已下线实例,业务重试再放大;配置高频发布时,推送量约等于变更次数乘订阅实例数,服务端和客户端会同时变成热点。
实战场景
一、告警规则照搬来的指标名,从未触发过
现象:某团队按社区 dashboard 建了一批 Nacos 告警。一次真实故障(推送失败导致调用方打到已下线实例)持续 20 分钟,所有告警静默。事后检查规则表达式,引用了 nacos_config_failed_push_total 这类并不存在的指标名;Prometheus 里对应序列为空,规则永远评估为空结果。
排查:Nacos 的指标形态是“一个指标 + module/name 标签”,先核对再建规则。
| 定位层 | 取证据 | 判定 |
|---|---|---|
| 指标是否真暴露 | curl .../nacos/actuator/prometheus | grep nacos_monitor | 无输出 → Actuator 未开 exposure.include=prometheus |
| 路径是否正确 | 上下文路径来自 nacos.server.contextPath,默认带 /nacos | 直接写 /actuator/prometheus 会 404 |
| 名字与 label | nacos_monitor{module="naming",name="serviceCount"} 这类完整形式 | serviceCount、publish 是 label 值,不是指标名 |
| 版本差异 | 3.3+ 客户端指标经 Micrometer 导出;3.2 及更早名称与单位不同 | 升级后 dashboard 先核对,不要照搬 |
| 是否根本不存在 | 健康/不健康实例数、心跳超时数、Distro 同步延迟、配置侧 failedPush | 这些没有官方稳定的单一指标名 |
最后一行是关键:这些量要靠 ops API(/nacos/v3/admin/ns/ops/metrics?onlyStatus=false)、按服务查询、逐节点 serviceCount/ipCount 对照、naming-server.log、notifyTask/dumpTask 堆积和 nacos_exception{module="config"} 来判断;查不到就写“以实际暴露为准”,不要给它们编一个不存在的指标名。
对症做法:
bash
# 1. 建规则前先列出真实序列,作为 dashboard 的唯一来源
curl -sS "http://10.0.0.11:8848/nacos/actuator/prometheus" \
| awk '/^nacos_monitor\{/{print}' | sed 's/ .*//' | sort -u | head -50
# 2. 无官方指标的项,用 ops API + 日志做导出脚本或自建埋点,明确标注来源
curl -sS -H "accessToken: $ACCESS_TOKEN" \
"http://10.0.0.11:8848/nacos/v3/admin/ns/ops/metrics?onlyStatus=false" > nacos_ops_metrics.jsonyaml
# 3. 规则要用“完整 label 形式”,并在注释里写清 label 含义与版本
- alert: NacosPushFailed
expr: rate(nacos_monitor{module="naming",name="failedPush"}[2m]) > 5 # 经验阈值,需按订阅规模校准
labels: { scope: "nacos-naming" }
annotations: { runbook: "见本专栏 05-高可用与容量规划 的雪崩链一节" }
# 4. 空序列的自检:任何 expr 引用了从未出现过的序列,纳入规则体检
- record: metric_absent_check
expr: absent(nacos_monitor{module="naming",name="failedPush"})absent() 规则值得单独留着:它把“指标不存在”变成一条告警,而不是静默的无数据。
复盘要点:判据是“每条告警规则都被触发过一次”:用故障演练或人为注入验证规则可触发,触发不了的规则要么修表达式要么删掉。dashboard 与规则文件要纳入版本管理,并在 Nacos 小版本升级后重跑一次序列清单 diff——指标名变化通常不会出现在升级说明里。
二、GC 停顿 2 秒,监控红了一片但业务没坏
现象:夜批任务时段,Nacos 节点 Young GC 停顿累计接近 2 秒。控制台与监控同时报“实例数骤降”“推送失败”,值班按 P1 拉起全员;实际业务侧“无可用实例”错误率只有 0.02%,用户几乎无感。恢复后复盘发现,告警全是资源层的。
排查:先分清症状与原因。
| 定位层 | 指标/证据 | 结论口径 |
|---|---|---|
| 业务面(症状) | 调用方“无可用实例”错误率、注册后首次可调用延迟(APM/自建) | 用户是否受影响,只看这一层定级 |
| 连接面 | nacos_monitor{module="core",name="longConnection"} 与 ops API 的 clientCount 是否匹配、grpc_server_executor 的 active/queue | 连接数与客户端数不匹配说明有未清理连接或重连风暴 |
| 命名服务 | ipCount、totalPush、failedPush、emptyPush、avgPushCost、pushPendingTaskCount | ipCount 骤降 + 待推送堆积是回路已经形成 |
| 进程余量 | jvm_gc_pause_seconds、jvm_memory_used_bytes、system_load_average_1m、process_files_open_files | GC 停顿接近心跳窗口(15s/30s)就会制造误判 |
| 依赖 | MySQL Threads_connected/慢查询/Seconds_Behind_Source | 配置侧变慢的另一条链 |
回路是 连接断开 → 重连风暴 + 心跳丢失 → 实例判不健康 → 流量集中 → 剩余过载 → 更多心跳超时。GC 停顿只是把第一环提前触发,本身不是用户可见故障。
对症做法:
yaml
# 1. 定级按症状:只有业务面指标进 P1/P2;CPU、GC 进 P3 或作为解释性面板
- alert: RegistryImpactUser # P1:调用方无可用实例
expr: rate(app_no_available_instance_total[2m]) / rate(app_request_total[2m]) > 0.01
for: 2m
- alert: NacosGcPauseHigh # P3:解释性告警,不叫人
expr: histogram_quantile(0.99, rate(jvm_gc_pause_seconds_bucket[5m])) > 0.5
for: 10mtext
2. 处置顺序先切断回路,再扩容:修 LB 空闲超时、放通 9848、给客户端重连加退避与抖动。
3. 直接重启 Nacos 会让所有客户端同时重连,把雪崩推得更高——这是最常见的错误处置。
4. 同根因告警做分组与抑制:业务面告警触发时抑制资源面通知,维护窗口内静默。
5. GC 停顿与心跳窗口的关系要写进容量结论:停顿 p99 必须远小于 15s,
否则把堆大小、GC 收集器或节点容量调整作为整改项。复盘要点:判据是“告警是否只反映用户可感知的变化”:把每条告警按症状/原因分层,资源类不进叫醒人的通道。真正要盯的是 ipCount 骤降、failedPush/待推送上升、节点计数分叉、leader 变化这类先兆——它们比业务错误率早几十秒到几分钟,适合做预警而不是事故通报。
三、配置历史表把发布拖到 8 秒
现象:配置发布耗时从平均 200ms 涨到 8s,notifyTask、dumpTask 持续堆积,新实例启动时 dump 也变慢。MySQL 侧出现 his_config_info 相关慢查询,单表行数已经到千万级。
排查:配置的写路径一定落 MySQL,节点只是缓存与通知。
| 定位层 | 取证据 | 判定 |
|---|---|---|
| 表体量 | config_info、his_config_info、config_info_gray 的行数与体积 | 历史表占绝对多数 → 清理缺失 |
| 慢查询 | 慢日志 digest、SHOW FULL PROCESSLIST | 按 dataId 查历史/全表扫描是主因 |
| 连接 | Threads_connected、Threads_running、连接池等待 | 打满后配置写与 dump 同时变慢 |
| 通知堆积 | notifyTask/notifyClientTask、nacos_timer{module="config"} 的 writeConfigRt/notifyRt/dumpRt | 写耗时与通知耗时同步上升 |
| 灰度残留 | 灰度版本条目数量 | 长期不清理的灰度会持续放大体积 |
| 异常 | nacos_exception{module="config"}、客户端 config.log | 没有官方单一 failedPush,用这些判断 |
对症做法:
sql
-- 1. 限制历史保留:按版本默认策略清理过期历史(保留期示例,按合规校准)
DELETE FROM his_config_info WHERE gmt_modified < DATE_SUB(NOW(), INTERVAL 30 DAY) LIMIT 1000;
-- 分批删除,避免一次性大事务;删除窗口避开发布高峰
-- 2. 确认索引:按 dataId + gid 查询必须走索引,不要靠全表扫描
SHOW INDEX FROM his_config_info;
-- 3. 清理长期残留的灰度版本
SELECT COUNT(*) FROM config_info_gray;text
4. 发布纪律:配置变更是低频人工/发布动作,批量发布分批(每批 ≤ 20 个 dataId,间隔 1–2s);
推送量约等于“变更次数 × 订阅实例数”,高频写会把服务端和客户端同时打成热点。
5. 备份按“MySQL 是配置真相”做:全量 + binlog;
恢复演练包含“只恢复配置表”和“整库恢复”两种,顺序是先 MySQL、再节点、最后客户端。
6. 告警加两条:his_config_info 行数增长斜率、writeConfigRt p99 > 1s。复盘要点:Nacos 集群高可用不等于配置存储高可用——MySQL 挂了配置写不了,这是架构事实,要在容量与故障预案里单独列出。判据是“发布耗时 p99”与“dump 成功”两条:前者反映日常体验,后者反映新实例能否起来;两者都要在业务错误率变化之前告警。相关发布与回滚动作见 配置中心,容量口径见 高可用与容量规划。
最小上手
以下命令按 3.x 写;2.x 把 v3 路径换成对应版本,并先确认 actuator 已暴露。
bash
# 指标端点:应看到 # HELP 和 nacos_monitor
curl -sS "http://nacos.example.com:8848/nacos/actuator/prometheus" | grep -E '^(# HELP|nacos_monitor)' | head
# readiness:期望 200;鉴权开启时带 accessToken
curl -sS -o /dev/null -w '%{http_code}\n' "http://nacos.example.com:8848/nacos/v3/admin/core/state/readiness"
# 连接与端口:8848 HTTP、9848 客户端 gRPC、9849 集群 gRPC;7848 仅集群/Raft
for p in 8848 9848 9849 7848; do nc -vz nacos.example.com "$p"; done
ss -tn state established '( sport = :9848 )' | tail -n +2 | wc -l # 服务端已建立连接数
# 客户端缓存时间(Linux;macOS 用 stat)
find ~/nacos -type f -printf '%TY-%Tm-%Td %TH:%TM %p\n' 2>/dev/null | sort | tail
# 服务端日志关键字;文件名以发行包 conf/logback*.xml 为准
grep -Ei 'PUSH-FAIL|reconnect|heartbeat|expired|dump|notify' "$NACOS_HOME"/logs/naming-push.log "$NACOS_HOME"/logs/naming-server.log "$NACOS_HOME"/logs/config-server.log 2>/dev/null | tail -50
# 3.x 运维计数;onlyStatus=false 才返回明细
curl -sS -H "accessToken: $ACCESS_TOKEN" "http://nacos.example.com:8848/nacos/v3/admin/ns/ops/metrics?onlyStatus=false"Prometheus 直接抓每个 Nacos 节点:
yaml
scrape_configs:
- job_name: nacos
metrics_path: /nacos/actuator/prometheus
static_configs:
- targets: ["10.0.0.11:8848", "10.0.0.12:8848", "10.0.0.13:8848"]MySQL 侧至少看连接、慢查询和配置表体量:
bash
mysql -h "$DB_HOST" -u "$DB_USER" -p "$DB_NAME" -e "
SHOW GLOBAL STATUS WHERE Variable_name IN ('Threads_connected','Threads_running','Aborted_connects');
SHOW FULL PROCESSLIST;
SELECT DIGEST_TEXT, COUNT_STAR, ROUND(SUM_TIMER_WAIT/1e12,2) total_sec
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC LIMIT 10;
SELECT table_name, table_rows, ROUND(data_length/1024/1024,1) data_mb
FROM information_schema.tables
WHERE table_schema=DATABASE() AND table_name IN ('config_info','his_config_info','config_info_gray');
"跑通的判据:/prometheus 有 # HELP 和 nacos_monitor 序列;readiness 返回 200;ops metrics 的 serviceCount/instanceCount 非空;nc 全部 succeeded,ss 连接数大于 0 且与客户端规模同量级;SQL 能返回行数,日志 grep 能定位到具体实例而不是空输出。
生产动作
以下阈值均为起点,按自己的基线校准;告警要带节点、服务名、订阅者 IP 或 dataId,不要只报集群汇总。
| 告警 | 指标/条件 | 级别 | 先做什么 |
|---|---|---|---|
| 集群不可用 | 2/3 节点 readiness 失败持续 1m,或持久实例无 leader、nacos_monitor_summary 显示 apply 停滞 | P0 | 查 MySQL、7848、quorum;不要同时重启所有节点 |
| 实例骤降 | ipCount 或 ops instanceCount 5m 内降超 20%,伴随 emptyPush 上升 | P0 | 查 9848、LB 空闲超时、心跳与 GC;先确认是否误删或合法缩容 |
| 推送失败/积压 | failedPush 速率超基线,pushPendingTaskCount 持续上升 5m | P1 | 定位订阅者 IP、gRPC 错误、客户端 GC;隔离异常客户端 |
| 连接异常 | longConnection 5m 内降超 30%,或与 SDK 客户端数明显不匹配 | P1 | 查 9848、LB、客户端版本与重连、直接内存和 fd |
| 配置通知/dump 积压 | notifyTask/notifyClientTask/dumpTask 持续上升,notifyRt/dumpRt 超基线 2 倍 | P1 | 查 MySQL 慢查询、连接池、磁盘和发布频率;不要先重启 |
| 配置发布异常 | publish 失败或 writeConfigRt 超基线 2 倍,nacos_exception{module="config"} 上升 | P1 | 查 MySQL 锁、磁盘、历史表;暂停高频发布 |
| MySQL 压力 | 连接使用率超 80% 持续 5m、慢查询增量上升、复制延迟超 30s | P1 | 先处理 DB 与慢 SQL;限制配置写入,不重启 Nacos |
| JVM/资源 | 老年代超 85%、Full GC 停顿超 1s、直接内存接近上限、fd 超 80% | P1 | 查泄漏与堆外;逐台摘流量滚动重启 |
| 生效时延 | 发布到生效 p99 超基线,或客户端快照超过约定时长未更新 | P2 | 查推送连接、快照时间、刷新方式与坐标 |
| 表/磁盘增长 | his_config_info/config_info_gray 增长超基线,或磁盘超 70%/85% | P2 | 审批后归档或清理,控制发布频率;不要直接删表 |
排障按「现象 → 证据 → 判断」走:
| 现象 | 证据 | 判断 |
|---|---|---|
| 实例突降/调用无实例 | nc 9848、LB 空闲超时、ss 连接数、longConnection、心跳与 GC 日志 | 先分「连接断了」还是「实例被合法摘除」;连接断查网络与接入层,连接在则查心跳、GC、推空保护 |
| 配置不生效 | namespace/group/dataId、spring.config.import、@RefreshScope、快照 mtime、notifyTask/nacos_exception、推送失败日志 | 坐标错或没导入是「读不到」;读到了不刷新查刷新方式与优先级;多实例不一致查推送 |
| 连接数异常 | 客户端版本、remote.log 重连、直接内存、fd、每个客户端对几个节点建连 | 先排除版本与重连风暴,再看容量;不要只调大 fd |
处置顺序固定:先恢复 MySQL 和 quorum,再控制客户端重连节奏(修 LB 超时、放通 9848、退避加 jitter、逐台重启),最后才扩容或调推送/发布频率。不要先重启 Nacos;重启会让所有客户端同时重连,也会清空本地缓存,可能把局部问题变成全局问题。恢复后确认客户端快照时间、实例名单和配置生效时延都回到基线,再把触发条件写回 runbook。
边界
优势是注册与配置一体、临时实例 AP + 持久实例 CP、gRPC 推送、生态和运维成本相对低;代价是长连接占直接内存和 fd,配置真相强依赖 MySQL,推送量随订阅数放大,3.x 的端口/API/控制台变化带来升级成本。
| 判断维度 | 适用 | 不适用 |
|---|---|---|
| 规模 | 客户端进程数百到数千、服务数百,且做过单节点压测 | 十万级长连接、多租户大集群,未做分片或压测 |
| 一致性 | 临时实例可接受秒级旧视图;持久实例只用于少量必须保留的名单 | 要求所有读强一致、不能接受旧视图 |
| 变更频率 | 人工/发布式低频配置变更 | 每秒级 KV 写入、高频配置发布 |
| 团队能力 | 能维护 3 节点 + MySQL + JVM/监控 | 没有 DBA/监控,指望开箱自愈 |
按约束选型,不问谁更强:K8s 生态、强一致的小规模元数据看 etcd;重审批、重灰度、重审计的配置治理看 Apollo;多数据中心、DNS/服务网格看 Consul;Spring Cloud/Dubbo、注册配置一体且团队小,Nacos 的运维面最少。
讲清楚
Nacos 监控要盯连接、实例、配置三条链。连接链看长连接数与客户端数是否匹配,以及 9848、负载均衡空闲超时;连接一断,心跳丢失会让实例被摘除,流量集中到剩余实例,过载又制造更多心跳超时,形成正反馈。实例链看实例数和推送失败,配置链看通知与落盘积压、异常计数和数据库慢查询。业务面的「无实例」错误率和配置生效时延是最终判据。处置先恢复数据库与多数派,再控制客户端重连,最后才扩容或重启;先重启 Nacos 常把局部故障放大成雪崩。