Java SDK 客户端指标
从 Nacos 3.3 开始,nacos-client 不再强依赖 io.prometheus:simpleclient。所有客户端指标都通过 Micrometer 的 Metrics.globalRegistry 记录,SDK 保持轻量,也不会强制绑定任何指标后端。
是否上报由 registry 决定,而不是由客户端决定:
- 未注册任何
MeterRegistry时,记录调用是安全的 no-op。 - 应用一旦注册具体的 registry,所有 nacos 客户端指标会自动流入其中。
1. 开启客户端指标
1.1. enableClientMetrics 开关
客户端属性 enableClientMetrics(PropertyKeyConst.ENABLE_CLIENT_METRICS)控制 NamingService 与 ConfigService 的记录点,包括 naming HTTP 请求 timer、naming 失败请求 counter、config 监听数 gauge 以及 naming 服务信息 gauge,默认值为 true。若应用有其他自有的指标采集方案,可以显式关闭以跳过这些记录调用:
enableClientMetrics=false多数场景保持默认即可:未注册 registry 时,记录调用本身开销极低。
1.2. Spring Boot 应用
Spring Boot 会为所有支持的后端自动装配 MeterRegistry bean,并在启动时把它加入 Metrics.globalRegistry。引入 actuator 与 Prometheus registry starter:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId></dependency>再暴露 scrape 端点:
management.endpoints.web.exposure.include=health,info,prometheusNacos 客户端指标会与应用自身指标一起出现在 /actuator/prometheus,无需 Nacos 侧的额外配置。
1.3. 非 Spring 应用
在创建任何 NamingService 或 ConfigService 之前,将具体的 MeterRegistry 注册到 Metrics.globalRegistry。注册时机不受限制:先创建的 meter 会在 registry 加入 composite 后立即被采集。
import io.micrometer.core.instrument.Metrics;import io.micrometer.prometheusmetrics.PrometheusConfig;import io.micrometer.prometheusmetrics.PrometheusMeterRegistry;
PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);Metrics.globalRegistry.add(registry);
// 通过任意 HTTP 端点暴露 registry.scrape() 的结果。如果应用已经为其他库维护了 MeterRegistry,直接复用即可:把同一个 registry 实例加入 Metrics.globalRegistry,Nacos 客户端指标会与应用其他指标一起被采集。
1.4. 选择合适的 Prometheus registry 制品
Micrometer 提供两个 Prometheus registry,nacos-client 两者都支持:
| 制品 | 底层 Prometheus 客户端 | 何时选择 |
|---|---|---|
io.micrometer:micrometer-registry-prometheus | io.prometheus:prometheus-metrics-core(新客户端) | 新应用,或已经使用新 Prometheus 客户端的应用。 |
io.micrometer:micrometer-registry-prometheus-simpleclient | io.prometheus:simpleclient(旧客户端) | 因其他库兼容性要求,必须保留旧 Prometheus 客户端的应用。 |
二者只选其一。两个制品基于不同的 Prometheus registry 类型——新客户端的 PrometheusRegistry 与旧客户端的 CollectorRegistry——本就无法共享同一个 registry;同时引入两者只会让 classpath 上多出第二套 Prometheus 客户端,没有任何收益。
2. 单独引入 io.prometheus:simpleclient 不再有效
在 Nacos 3.3 之前,只要把 io.prometheus:simpleclient 加进 classpath,客户端就会自行创建并注册 collector,nacos_monitor、nacos_client_request 等指标就能被抓取到。
从 Nacos 3.3 开始,这一假设不再成立:
nacos-client不再创建任何 Prometheus collector;io.prometheus:simpleclient自身不认识 Micrometer,不会往Metrics.globalRegistry注册任何东西;- 升级后如果只保留了裸的
simpleclient依赖,客户端指标会静默消失。
若要继续导出 Nacos 客户端指标,请把裸的 simpleclient 依赖替换为 1.4 节 中的 Micrometer Prometheus registry,并确保它已经注册到 Metrics.globalRegistry。
3. 指标一览
下列名称与标签即为 Prometheus scrape 端点上出现的形式。Micrometer 会为 Timer 追加基础单位后缀(_seconds),但不会为名字本身已经以 _total 结尾的 Counter 再追加一次 _total。
3.1. Gauge
| 序列 | 标签 | 含义 |
|---|---|---|
nacos_monitor | module="naming", name="serviceInfoMapSize" | 客户端缓存中当前订阅的服务数。 |
nacos_monitor | module="config", name="listenConfigCount" | ConfigService 当前监听的配置数。 |
nacos_monitor | module="ai", name="agentWatchIntentCount" | 当前跟踪的 AI Agent watch intent 数。 |
nacos_monitor | module="ai", name="agentWatchPendingCount" | 当前待派发的 AI Agent watch 回调数。 |
nacos_monitor | module="ai", name="agentWatchDirtyCount" | 当前被标记为 dirty 的 AI Agent watch 条目数。 |
nacos_monitor 保持历史名称与标签结构,Nacos 2.x 上构建的 dashboard 可继续读取同名序列。
3.2. 请求 Timer
nacos_client_request 在 Prometheus 上以 nacos_client_request_seconds_{bucket,count,sum,max} 形式导出。
| 标签 | 取值 |
|---|---|
module | naming(默认装配)、config(仅对直接经由手动构造的 MetricsHttpAgent 发起的调用出现;常规 ConfigService 无法产生,见上方说明) |
method | GET、POST、DELETE |
url | naming:完整构造出的请求 URL(服务器地址 + 路径,基数高,聚合时需谨慎);config:请求路径,例如 /cs/configs |
code | HTTP 状态码字符串。naming 路径在拿到响应前抛出异常时不会产生 timer 序列(请求直接失败、无序列);手动装配的 config 路径中 MetricsHttpAgent 会在 finally 块里记录 code="NA" |
从 Nacos 3.3 开始,method 标签反映真实 HTTP 方法。此前 httpPost 与 httpDelete 都被记录为 method="GET",按 method 分组的告警与 dashboard 在升级后会看到流量重新分布。
Bucket 边界沿用 Prometheus Java 客户端默认值,通过 Micrometer service level objectives 暴露,histogram_quantile() 可继续使用:
le="0.005" le="0.01" le="0.025" le="0.05" le="0.075" le="0.1"le="0.25" le="0.5" le="0.75" le="1.0" le="2.5" le="5.0" le="7.5" le="10.0" le="+Inf"3.3. Naming 请求失败 Counter
nacos_client_naming_request_failed_total 是 Micrometer Counter。因为基础名已经以 _total 结尾,导出序列保持同名,不会再叠加后缀。
| 标签 | 取值 |
|---|---|
module | naming |
req_class | 失败 gRPC 请求的 simple class name,例如 InstanceRequest |
res_status | 响应 result code;未拿到响应时为 NONE |
res_code | 响应 error code;未拿到响应时为 NONE |
err_class | 抛出异常的 simple class name;未抛异常时为 NONE |
3.4. AI watch 事件 Counter
nacos_client_ai_watch_events_total 统计 AI Agent watch 事件。两个标签都是封闭枚举,基数受控。
| 标签 | 取值 |
|---|---|
event | discover_refresh、fingerprint_mismatch、retry、capacity_rejection、listener_callback |
result | success、unchanged、mismatch、scheduled、rejected、failed |
4. 从 Nacos 3.2 及更早版本迁移
在 Nacos 3.2 已有的指标中,线上格式变化只涉及请求 timer(见 4.1、4.2 节)。既有的 naming/config gauge(nacos_monitor)与 naming 失败请求 counter 保持名称与标签不变,基于它们的 dashboard 无需修改。注意 AI watch 指标、nacos_client_request_seconds_max 以及修正后的 method 标签行为都是 3.3 新增,3.2 上没有对应序列。
4.1. nacos_client_request 系列被重命名
| 迁移前 | 迁移后 |
|---|---|
nacos_client_request_bucket | nacos_client_request_seconds_bucket |
nacos_client_request_count | nacos_client_request_seconds_count |
nacos_client_request_sum | nacos_client_request_seconds_sum |
| — | nacos_client_request_seconds_max(新增) |
重命名来自 Micrometer:它会为 Timer 序列追加基础单位。所有引用旧名的 PromQL 表达式、告警规则、dashboard 面板都需要同步更新。
4.2. _sum 单位从毫秒变为秒
Nacos 3.3 之前,客户端将 System.currentTimeMillis() - start ——一个毫秒数——直接喂给一个 bucket 边界以秒定义的 Prometheus histogram。观测值与边界做的是数值比较,因此:
- 大于
10的观测(慢于 10 ms 的请求,长尾部分)只会落到le="+Inf"; - 不大于
10的观测(10 ms 及更快的请求,常见情形)会落进有限 bucket——但这些 bucket 的名义量纲是秒。一个 3 ms 的请求会被计入le="5.0",一个名义上代表 5 秒的 bucket。
无论哪种情况,分布都是无意义的:毫秒量级的观测值被拿来与 Prometheus 默认 latency bucket 边界(按秒刻度排布)做数值比较。旧序列名 nacos_client_request_sum 本身并不声明任何单位——错位发生在记录的观测值里,不在名字上。
从 Nacos 3.3 开始,耗时通过 Micrometer Timer 记录:
nacos_client_request_seconds_sum单位为秒;- Bucket 会真正被填充,
histogram_quantile()首次给出可用的分位数。
4.3. 保留旧 dashboard 的 recording rule
如果暂时无法重写全部 dashboard,可通过 recording rule 保留旧名。将规则部署在抓取客户端指标的 Prometheus 实例上:
groups: - name: nacos_client_request_migration interval: 30s rules: - record: nacos_client_request_count expr: nacos_client_request_seconds_count - record: nacos_client_request_sum expr: nacos_client_request_seconds_sum * 1000 - record: nacos_client_request_bucket expr: nacos_client_request_seconds_bucket* 1000 用来把新的秒制 _sum 换算回旧 dashboard 期望的毫秒制。Bucket 边界未变,nacos_client_request_bucket 可直接沿用。
4.4. PromQL 迁移示例
| 目的 | 迁移前 | 迁移后 |
|---|---|---|
| 按 module 统计 QPS | sum(rate(nacos_client_request_count[1m])) by (module) | sum(rate(nacos_client_request_seconds_count[1m])) by (module) |
| 平均耗时(毫秒) | sum(rate(nacos_client_request_sum[5m])) / sum(rate(nacos_client_request_count[5m])) | 1000 * sum(rate(nacos_client_request_seconds_sum[5m])) / sum(rate(nacos_client_request_seconds_count[5m])) |
| p99 耗时 | histogram_quantile(0.99, sum(rate(nacos_client_request_bucket[5m])) by (le)) | histogram_quantile(0.99, sum(rate(nacos_client_request_seconds_bucket[5m])) by (le)) |
| 按 method 统计错误率 | sum(rate(nacos_client_request_count{code!="200",code!="NA"}[5m])) by (method) | sum(rate(nacos_client_request_seconds_count{code!="200",code!="NA"}[5m])) by (method) |
p99 结果单位为秒。若 dashboard 显示单位是毫秒,请在面板中乘以 1000。
5. 指标失败绝不影响业务请求
MetricsMonitor 中所有记录路径都会吞掉 Throwable,因此损坏的 registry 不会:
- 覆盖成功的业务结果(
MetricsHttpAgent的记录调用在finally块中执行); - 掩盖 HTTP 或 gRPC 调用抛出的原始异常;
- 取消上报指标的定时任务。
首次失败会通过 com.alibaba.nacos.client.monitor.MetricsMonitor 以 WARN 级别打印一次日志,后续失败会被抑制,避免刷爆客户端日志。若某次发布后指标不再上报,检查一次该日志并定位底层 registry 问题即可。
6. 排查建议
Prometheus scrape 输出中找不到 Nacos 客户端指标
确认 Metrics.globalRegistry 上确实注册了 MeterRegistry。Spring Boot 应用请检查 actuator starter 与 Micrometer Prometheus registry 都在 classpath 上;非 Spring 应用请确认注册代码在第一次调用 Nacos 客户端之前执行,且之后没有其他库清空 composite registry。
已设置 enableClientMetrics=true 但仍然没有数据
该属性只控制 SDK 内部是否调用记录点,并不负责注册后端。参考上一条。
只有部分客户端指标出现
Meter 是懒创建的:nacos_client_request_seconds_count{module="naming"} 只有在第一次 naming HTTP 调用之后才会出现,nacos_client_naming_request_failed_total 只有在真的发生 naming 请求失败之后才会出现。nacos_client_request_seconds_count{module="config"} 对常规 ConfigService 根本不会出现——见 3.2 节的说明。在断定指标坏了之前,先触发一次相应代码路径。
从 Nacos 3.2 升级后分位数看起来不对
参见 4.2 节。3.3 之前 histogram 用毫秒量级的观测值对比秒量级的 bucket 边界——10 ms 及更快的请求落进以秒解读的有限 bucket,更慢的堆积在 +Inf——旧分位数本就不可用;新分位数才是首次有意义的数据。
升级后 method 标签分布发生变化
从 Nacos 3.3 开始,httpPost 与 httpDelete 会以真实方法记录;此前它们都被记为 method="GET"。按 method 分组的 dashboard 会看到流量从 GET 迁移到 POST 与 DELETE,这是修复,不是回归。