监控与可观测性
目录
- 监控端点概览
- /varz — 服务器基础信息
- /routez — 集群路由
- /connz — 客户端连接
- /subsz — 订阅统计
- /jsz — JetStream 状态
- /jsz?streams=1 — Stream 列表
- /jsz?consumers=1 — Consumer 列表
- /healthz — 健康检查
- /leafz — Leaf Node 连接
- /gatewayz — Gateway 连接
- /accountz — 账号信息
- /statz — 统计信息
- 常用运维命令集合
- 告警指标建议
1. 监控端点概览
NATS Server 内置 HTTP 监控端口(默认 8222),无需额外安装即可使用。所有端点返回 JSON 格式。
# 启动 NATS Server 时开启监控端口
nats-server -m 8222
# 或在配置文件中
# nats-server.conf:
# monitor_port: 8222| 端点 | 说明 | 典型用途 |
|---|---|---|
/varz | 服务器基础指标 | 通用性能监控 |
/routez | 集群路由状态 | 集群健康检查 |
/connz | 客户端连接列表 | 连接问题排查 |
/subsz | 订阅统计 | Subject 分布分析 |
/jsz | JetStream 总览 | JetStream 健康监控 |
/healthz | 健康检查 | K8s 探针 |
/leafz | Leaf Node 连接 | Leaf Node 管理 |
/gatewayz | Gateway 连接 | 多集群监控 |
/accountz | 账号信息 | 多租户管理 |
/statz | 服务器统计 | 性能趋势 |
2. /varz — 服务器基础信息
URL: GET http://nats-server:8222/varz
说明: 返回 NATS Server 的核心运行指标,是最常用的监控端点,涵盖连接数、消息吞吐、内存、CPU 等关键信息。
关键字段解释
| 字段 | 类型 | 说明 |
|---|---|---|
server_id | string | Server 的唯一标识(启动时生成) |
server_name | string | 配置的 Server 名称(集群节点名) |
version | string | NATS Server 版本号 |
go | string | 编译使用的 Go 版本 |
host | string | 监听地址 |
port | int | 客户端连接端口 |
uptime | string | 运行时长(可读格式,如 "2d3h") |
mem | int | 当前内存使用字节数 |
cores | int | CPU 核心数 |
max_connections | int | 最大允许连接数 |
connections | int | 当前活跃连接数 |
total_connections | int | 历史累计连接总数 |
slow_consumers | int | 慢消费者数量(消息积压的连接数) |
subscriptions | int | 当前订阅总数 |
messages_in | int | 累计接收消息数 |
messages_out | int | 累计发送消息数 |
bytes_in | int | 累计接收字节数 |
bytes_out | int | 累计发送字节数 |
in_msgs | int | 实时指标:当前统计周期内接收消息数 |
out_msgs | int | 实时指标:当前统计周期内发送消息数 |
max_payload | int | 单条消息最大允许字节数 |
cluster | object | 集群信息(节点名、集群名等) |
jetstream | object | JetStream 启用状态和基础配置 |
示例响应(部分)
{
"server_id": "NBQXXXABCDEF123456",
"server_name": "nats-node-1",
"version": "2.10.14",
"proto": 1,
"go": "go1.21.5",
"host": "0.0.0.0",
"port": 4222,
"max_connections": 65536,
"ping_interval": 120000000000,
"ping_max": 2,
"http_host": "0.0.0.0",
"http_port": 8222,
"max_payload": 1048576,
"jetstream": {
"config": {
"max_memory": 4294967296,
"max_storage": 107374182400,
"store_dir": "/data/nats/jetstream"
},
"stats": {
"memory": 1048576,
"storage": 536870912,
"reserved_memory": 0,
"reserved_storage": 0,
"accounts": 1,
"ha_assets": 6,
"api": {
"total": 5678,
"errors": 2
}
}
},
"connections": 42,
"total_connections": 1024,
"routes": 2,
"remotes": 2,
"leafnodes": 0,
"in_msgs": 12345678,
"out_msgs": 12345678,
"in_bytes": 1234567890,
"out_bytes": 1234567890,
"slow_consumers": 0,
"subscriptions": 256,
"http_req_stats": {
"/varz": 100,
"/jsz": 50
},
"mem": 52428800,
"cores": 4,
"max_procs": 4,
"now": "2024-01-15T10:30:00.000Z",
"uptime": "2d3h14m22s",
"start": "2024-01-13T07:15:38.000Z"
}使用场景
# 快速查看服务器健康概览
curl -s http://nats:8222/varz | jq '{
version,
uptime,
connections,
slow_consumers,
messages_in,
mem_mb: (.mem / 1048576 | floor)
}'
# 监控消息吞吐趋势(通过对比两次采集的 in_msgs 差值计算 QPS)
# 推荐交给 Prometheus exporter 处理3. /routez — 集群路由
URL: GET http://nats-server:8222/routez
说明: 返回当前节点与其他集群成员之间的路由连接信息,用于验证集群拓扑和诊断节点间连接问题。
关键字段解释
| 字段 | 类型 | 说明 |
|---|---|---|
num_routes | int | 当前建立的路由连接数(正常值 = 集群节点数 - 1) |
routes | array | 每个路由连接的详情 |
routes[].rid | int | 路由 ID(内部标识) |
routes[].remote_id | string | 对端节点的 Server ID |
routes[].remote_name | string | 对端节点的配置名称 |
routes[].did_solicit | bool | 是否是本节点主动发起的连接 |
routes[].is_configured | bool | 是否在配置文件中显式配置的路由 |
routes[].ip | string | 对端 IP 地址 |
routes[].port | int | 对端路由端口 |
routes[].start | string | 路由建立时间 |
routes[].last_activity | string | 最后通信时间 |
routes[].rtt | string | 网络往返时延(Round-Trip Time),如 "1.2ms" |
routes[].uptime | string | 路由连接已持续时长 |
routes[].idle | string | 空闲时长(上次通信到现在) |
routes[].in_msgs | int | 从该路由收到的消息数 |
routes[].out_msgs | int | 向该路由发送的消息数 |
routes[].subscriptions | int | 通过此路由订阅的 Subject 数量 |
示例响应(部分)
{
"server_id": "NBQXXX-NODE-1",
"now": "2024-01-15T10:30:00Z",
"num_routes": 2,
"routes": [
{
"rid": 1,
"remote_id": "NBQXXX-NODE-2",
"remote_name": "nats-node-2",
"did_solicit": true,
"is_configured": true,
"ip": "10.0.0.2",
"port": 6222,
"start": "2024-01-13T07:15:40Z",
"last_activity": "2024-01-15T10:29:58Z",
"rtt": "0.8ms",
"uptime": "2d3h14m20s",
"idle": "2s",
"in_msgs": 5000000,
"out_msgs": 5000000,
"in_bytes": 500000000,
"out_bytes": 500000000,
"subscriptions": 128
},
{
"rid": 2,
"remote_id": "NBQXXX-NODE-3",
"remote_name": "nats-node-3",
"did_solicit": true,
"is_configured": true,
"ip": "10.0.0.3",
"port": 6222,
"rtt": "1.1ms",
"uptime": "2d3h14m20s",
"idle": "1s",
"in_msgs": 4900000,
"out_msgs": 4900000
}
]
}使用场景
# 检查集群所有路由是否已建立(3节点集群应显示 num_routes=2)
curl -s http://nats:8222/routez | jq '{
num_routes,
routes: [.routes[] | {name: .remote_name, rtt, uptime, idle}]
}'
# 检查节点间 RTT 是否异常(>10ms 表示网络问题)
curl -s http://nats:8222/routez | jq '.routes[] | {name: .remote_name, rtt}'4. /connz — 客户端连接
URL: GET http://nats-server:8222/connz
参数:
?limit=N— 返回最多 N 个连接(默认 1024)?offset=N— 分页偏移量?sort=subs|msgs_from|msgs_to|bytes_from|bytes_to|idle|uptime|start— 排序字段?state=open|closed|all— 过滤连接状态?cid=N— 查询指定连接 ID?user=NAME— 按用户名过滤?name=PATTERN— 按连接名称过滤(支持通配符)?subs=1— 包含每个连接的订阅列表
说明: 列出所有客户端连接的详细信息,用于排查连接泄漏、慢消费者和高流量客户端。
关键字段解释
| 字段 | 说明 |
|---|---|
num_connections | 当前活跃连接总数 |
connections[].cid | 连接 ID(本次连接的唯一编号) |
connections[].name | 客户端连接名称(nats.Name() 设置的值) |
connections[].ip | 客户端 IP |
connections[].port | 客户端端口 |
connections[].start | 连接建立时间 |
connections[].uptime | 连接已持续时长 |
connections[].idle | 空闲时长 |
connections[].lang | 客户端语言(go、python、java 等) |
connections[].version | 客户端库版本 |
connections[].subscriptions | 该连接的订阅数量 |
connections[].in_msgs | 该连接收到的消息数 |
connections[].out_msgs | 该连接发送的消息数 |
connections[].pending_bytes | 待发送给此客户端的积压字节数(> 0 表示慢消费者) |
示例响应(部分)
{
"server_id": "NBQXXX-NODE-1",
"now": "2024-01-15T10:30:00Z",
"num_connections": 42,
"connections": [
{
"cid": 101,
"name": "order-service-prod-1",
"lang": "go",
"version": "1.36.0",
"ip": "10.0.1.100",
"port": 54321,
"start": "2024-01-15T08:00:00Z",
"uptime": "2h30m",
"idle": "100ms",
"in_msgs": 100000,
"out_msgs": 50000,
"in_bytes": 10485760,
"out_bytes": 5242880,
"subscriptions": 3,
"pending_bytes": 0,
"rtt": "0.5ms"
},
{
"cid": 102,
"name": "slow-consumer-worker",
"lang": "python",
"version": "2.3.0",
"ip": "10.0.1.200",
"pending_bytes": 5242880,
"subscriptions": 1
}
]
}使用场景
# 查找慢消费者(pending_bytes > 0)
curl -s "http://nats:8222/connz?limit=100" | \
jq '.connections[] | select(.pending_bytes > 0) | {name, ip, pending_bytes}'
# 按消息量排序,找到最活跃的连接
curl -s "http://nats:8222/connz?sort=msgs_to&limit=10" | \
jq '.connections[:5] | .[] | {name, lang, in_msgs, out_msgs}'
# 查找特定服务的连接
curl -s "http://nats:8222/connz?name=order-service*" | \
jq '.connections[] | {cid, name, uptime, subscriptions}'
# 查找空闲超过 1 小时的可疑连接(可能是连接泄漏)
curl -s "http://nats:8222/connz" | \
jq '.connections[] | select(.idle | test("^[1-9][0-9]*h")) | {name, ip, idle}'5. /subsz — 订阅统计
URL: GET http://nats-server:8222/subsz
参数:
?subs=1— 包含详细的订阅列表?offset=N— 分页偏移量?limit=N— 返回条数限制?test=SUBJECT— 测试指定 Subject 匹配到哪些订阅
说明: 提供当前所有订阅的统计信息,用于分析 Subject 路由分布和发现孤立订阅。
关键字段解释
| 字段 | 说明 |
|---|---|
num_subscriptions | 本节点当前订阅总数 |
num_cache | 路由缓存中的 Subject 数量 |
num_inserts | 历史订阅插入次数 |
num_removes | 历史订阅移除次数 |
num_matches | 路由匹配总次数(消息分发性能参考) |
cache_hit_rate | 路由缓存命中率(越高越好,> 90% 正常) |
max_fanout | 历史最大 Fanout 值(一条消息分发到的最多订阅数) |
avg_fanout | 平均 Fanout 值 |
total | 含集群路由后的全局订阅总数 |
示例响应
{
"num_subscriptions": 256,
"num_cache": 128,
"num_inserts": 10000,
"num_removes": 9744,
"num_matches": 5000000,
"cache_hit_rate": 0.987,
"max_fanout": 50,
"avg_fanout": 1.5,
"total": 768
}使用场景
# 查看订阅统计摘要
curl -s http://nats:8222/subsz | jq '{
subscriptions: .num_subscriptions,
cache_hit_rate: .cache_hit_rate,
max_fanout: .max_fanout,
avg_fanout: .avg_fanout
}'
# 测试某个 Subject 会被哪些订阅接收
curl -s "http://nats:8222/subsz?test=orders.placed" | jq .6. /jsz — JetStream 状态
URL: GET http://nats-server:8222/jsz
说明: JetStream 的核心监控端点,提供 JetStream 引擎状态、Meta Cluster 的 Raft 状态、存储用量等关键信息。
关键字段解释
| 字段 | 说明 |
|---|---|
config.max_memory | JetStream 最大内存使用配置(字节) |
config.max_storage | JetStream 最大磁盘使用配置(字节) |
config.store_dir | JetStream 数据存储目录 |
memory | 当前内存使用量(字节) |
storage | 当前磁盘使用量(字节) |
reserved_memory | 预留内存(尚未实际使用) |
reserved_storage | 预留磁盘(尚未实际使用) |
accounts | 启用 JetStream 的账号数量 |
ha_assets | HA 资源数量(Replicas>1 的 Stream 和 Consumer 之和) |
api.total | JetStream API 累计调用次数 |
api.errors | JetStream API 累计错误次数 |
meta_cluster.name | 集群名称 |
meta_cluster.leader | 当前 Meta Raft Leader 节点名 |
meta_cluster.peer | 本节点在集群中的 Peer ID |
meta_cluster.replicas | 集群所有节点的 Raft 状态列表 |
meta_cluster.replicas[].name | 节点名称 |
meta_cluster.replicas[].current | 是否跟上 Leader(true=已同步) |
meta_cluster.replicas[].active | 距最后一次 Raft 活动的时间 |
meta_cluster.replicas[].lag | 日志落后 Leader 的条目数(应接近 0) |
streams | 本节点负责的 Stream 总数 |
consumers | 本节点负责的 Consumer 总数 |
messages | 所有 Stream 的消息总数 |
bytes | 所有 Stream 的存储字节总量 |
示例响应(部分)
{
"server_id": "NBQXXX-NODE-1",
"now": "2024-01-15T10:30:00Z",
"config": {
"max_memory": 4294967296,
"max_storage": 107374182400,
"store_dir": "/data/nats/jetstream",
"sync_always": false,
"sync_interval": 2000000000,
"compress_ok": true
},
"memory": 104857600,
"storage": 10737418240,
"reserved_memory": 0,
"reserved_storage": 0,
"accounts": 1,
"ha_assets": 9,
"api": {
"total": 12345,
"errors": 3
},
"meta_cluster": {
"name": "prod-cluster",
"leader": "nats-node-1",
"peer": "NQJXXX...",
"replicas": [
{
"name": "nats-node-1",
"current": true,
"active": "50ms",
"lag": 0
},
{
"name": "nats-node-2",
"current": true,
"active": "60ms",
"lag": 0
},
{
"name": "nats-node-3",
"current": true,
"active": "55ms",
"lag": 0
}
]
},
"streams": 5,
"consumers": 12,
"messages": 2500000,
"bytes": 10737418240
}使用场景
# 查看 JetStream 健康摘要
curl -s http://nats:8222/jsz | jq '{
meta_leader: .meta_cluster.leader,
streams: .streams,
consumers: .consumers,
messages: .messages,
storage_gb: (.storage / 1073741824 | . * 100 | round / 100),
api_errors: .api.errors,
ha_assets: .ha_assets
}'
# 检查 Meta Cluster 所有节点是否同步(lag 应为 0)
curl -s http://nats:8222/jsz | jq '.meta_cluster.replicas[] | {name, current, lag, active}'
# 计算 JetStream 存储使用率
curl -s http://nats:8222/jsz | jq '{
used_gb: (.storage / 1073741824 | . * 100 | round / 100),
max_gb: (.config.max_storage / 1073741824 | . * 100 | round / 100),
usage_pct: (.storage / .config.max_storage * 100 | . * 10 | round / 10)
}'7. /jsz?streams=1 — 包含 Stream 列表
URL: GET http://nats-server:8222/jsz?streams=1
说明: 在 /jsz 基础上,附加返回所有 Stream 的详细配置和运行状态(包含 Raft 副本状态)。数据量较大,适合定期采集而非实时查询。
额外字段
返回的 JSON 在 /jsz 基础上增加 account_details[].stream_detail 数组:
{
"account_details": [
{
"name": "$G",
"stream_detail": [
{
"name": "ORDERS",
"created": "2024-01-01T00:00:00Z",
"config": {
"name": "ORDERS",
"subjects": ["orders.>"],
"retention": "limits",
"max_consumers": -1,
"max_msgs": 10000000,
"max_bytes": 10737418240,
"max_age": 604800000000000,
"max_msg_size": 1048576,
"storage": "file",
"replicas": 3,
"no_ack": false,
"discard": "old"
},
"state": {
"messages": 50000,
"bytes": 10485760,
"first_seq": 1,
"first_ts": "2024-01-10T00:00:00Z",
"last_seq": 50000,
"last_ts": "2024-01-15T10:29:59Z",
"num_deleted": 0,
"num_subjects": 10,
"consumer_count": 3
},
"cluster": {
"name": "prod-cluster",
"leader": "nats-node-2",
"replicas": [
{ "name": "nats-node-1", "current": true, "active": "20ms", "lag": 0 },
{ "name": "nats-node-3", "current": true, "active": "22ms", "lag": 0 }
]
}
}
]
}
]
}使用场景
# 列出所有 Stream 及其 Leader 分布
curl -s "http://nats:8222/jsz?streams=1" | \
jq '.account_details[0].stream_detail[] | {
name: .config.name,
messages: .state.messages,
bytes_mb: (.state.bytes / 1048576 | floor),
leader: .cluster.leader,
replicas: .config.replicas
}'
# 检查所有 Stream 中是否有副本落后(lag > 0)
curl -s "http://nats:8222/jsz?streams=1" | \
jq '.account_details[0].stream_detail[] |
{ stream: .config.name,
lagging_replicas: [
.cluster.replicas[]? | select(.lag > 100) |
{name, lag, active}
]
} | select(.lagging_replicas | length > 0)'8. /jsz?consumers=1 — 包含 Consumer 列表
URL: GET http://nats-server:8222/jsz?consumers=1
说明: 在 ?streams=1 基础上,进一步包含每个 Stream 下所有 Consumer 的详细状态,包含消费进度和积压量。
Consumer 关键字段
{
"name": "order-processor",
"stream_name": "ORDERS",
"created": "2024-01-10T00:00:00Z",
"config": {
"durable_name": "order-processor",
"deliver_policy": "all",
"ack_policy": "explicit",
"ack_wait": 30000000000,
"max_deliver": 3,
"filter_subject": "orders.placed",
"max_ack_pending": 1000
},
"delivered": {
"consumer_seq": 45000,
"stream_seq": 45000,
"last_active": "2024-01-15T10:29:59Z"
},
"ack_floor": {
"consumer_seq": 44900,
"stream_seq": 44900,
"last_active": "2024-01-15T10:29:58Z"
},
"num_ack_pending": 100,
"num_redelivered": 5,
"num_waiting": 0,
"num_pending": 1000,
"cluster": {
"leader": "nats-node-2"
}
}| 字段 | 说明 |
|---|---|
num_pending | 未被 Consumer 消费的消息数(消费积压量) |
num_ack_pending | 已投递但尚未 ACK 的消息数(处理中) |
num_redelivered | 因超时重投的消息数(>0 表示有处理失败) |
num_waiting | 等待新消息的 Pull Consumer 请求数 |
delivered.stream_seq | 已投递的最新 Stream 序列号 |
ack_floor.stream_seq | 已 ACK 的最低序列号(之前的消息都已 ACK) |
使用场景
# 查看所有 Consumer 的消费积压(num_pending > 0 表示有积压)
curl -s "http://nats:8222/jsz?consumers=1" | \
jq '[.account_details[0].stream_detail[].consumer_detail[]? |
{stream: .stream_name, consumer: .name, pending: .num_pending,
ack_pending: .num_ack_pending, redelivered: .num_redelivered}] |
sort_by(-.pending)'
# 找出积压超过 1000 条的 Consumer(需要扩容处理)
curl -s "http://nats:8222/jsz?consumers=1" | \
jq '[.account_details[0].stream_detail[].consumer_detail[]? |
select(.num_pending > 1000) |
{stream: .stream_name, consumer: .name, pending: .num_pending}]'
# 检查重投消息(num_redelivered 高表示处理失败率高)
curl -s "http://nats:8222/jsz?consumers=1" | \
jq '[.account_details[0].stream_detail[].consumer_detail[]? |
select(.num_redelivered > 0) |
{consumer: .name, redelivered: .num_redelivered}]'9. /healthz — 健康检查
NATS 提供多个 /healthz 变体,分别适用于不同的探针场景。
9.1 /healthz — 基础健康检查
URL: GET http://nats-server:8222/healthz
说明: 最基础的健康检查,只要 NATS Server 进程正常运行就返回 200 OK。
{ "status": "ok", "healthz": "ok" }HTTP 状态码:
200— 服务器正常503— 服务器不健康
适用探针: Kubernetes liveness probe(存活探针)
livenessProbe:
httpGet:
path: /healthz
port: 8222
initialDelaySeconds: 10
periodSeconds: 30
failureThreshold: 39.2 /healthz?js-server-only=true — JetStream 本节点健康
URL: GET http://nats-server:8222/healthz?js-server-only=true
说明: 检查本节点的 JetStream 是否已初始化就绪。与 ?js-enabled-only=true 不同,此选项不等待 Meta Cluster 选出 Leader,只检查本节点 JetStream 引擎是否已启动。
推荐用于: Kubernetes readiness probe(就绪探针)
readinessProbe:
httpGet:
path: /healthz?js-server-only=true
port: 8222
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 3为什么推荐 js-server-only=true 而不是默认 /healthz?
在 NATS 集群启动时,各节点需要一段时间完成 Raft 选举。使用 js-server-only=true 可以让节点在本地 JetStream 就绪后立即接受流量,而不必等待整个集群选举完成(这可能需要几秒到几十秒)。这能减少滚动部署时的等待时间。
9.3 /healthz?js-enabled-only=true — JetStream 是否启用
URL: GET http://nats-server:8222/healthz?js-enabled-only=true
说明: 检查 JetStream 是否已启用并完全就绪(包括等待 Meta Cluster 选出 Leader)。在集群刚启动时,此检查可能返回 503,直到集群完成选举。
适用场景: 用于验证集群 JetStream 已完全可用的一次性检查(不适合做 readiness probe,因为可能长时间 503)
# 等待集群完全就绪
until curl -sf "http://nats:8222/healthz?js-enabled-only=true"; do
echo "等待 JetStream 就绪..."
sleep 2
done
echo "JetStream 已就绪"9.4 健康检查响应状态对比
| 端点 | 200 条件 | 503 条件 | 适用场景 |
|---|---|---|---|
/healthz | 进程存活 | 进程崩溃 | Liveness Probe |
/healthz?js-server-only=true | 本节点 JetStream 启动 | 本节点 JetStream 未启动 | Readiness Probe |
/healthz?js-enabled-only=true | 集群 JetStream 就绪 | 集群 JetStream 未就绪 | 部署验证 |
10. /leafz — Leaf Node 连接
URL: GET http://nats-server:8222/leafz
说明: 返回所有 Leaf Node 连接的详情。Leaf Node 是一种轻量级的 NATS Server,用于边缘场景或多云连接,通过单一 TLS 出站连接接入中心集群。
关键字段
{
"now": "2024-01-15T10:30:00Z",
"leafnodes": 3,
"leaves": [
{
"name": "edge-beijing",
"is_spoke": false,
"account": "$G",
"ip": "1.2.3.4",
"port": 7422,
"rtt": "15ms",
"in_msgs": 100000,
"out_msgs": 50000,
"subscriptions": 10
}
]
}| 字段 | 说明 |
|---|---|
leafnodes | 当前连接的 Leaf Node 总数 |
leaves[].name | Leaf Node 名称 |
leaves[].is_spoke | 本节点是否是 Spoke(出站连接发起方) |
leaves[].rtt | 与 Leaf Node 的网络延迟 |
leaves[].subscriptions | 通过此 Leaf 传播的订阅数 |
11. /gatewayz — Gateway 连接
URL: GET http://nats-server:8222/gatewayz
说明: 在多集群(Super Cluster)架构中,Gateway 是集群间的互联通道。此端点返回所有 Gateway 连接状态。
关键字段
{
"server_id": "NBQXXX-NODE-1",
"now": "2024-01-15T10:30:00Z",
"name": "cluster-beijing",
"outbound_gateways": {
"cluster-shanghai": {
"connection": {
"name": "cluster-shanghai",
"ip": "1.2.3.4",
"port": 7522,
"rtt": "5ms",
"uptime": "10h",
"in_msgs": 500000,
"out_msgs": 600000
}
}
},
"inbound_gateways": {
"cluster-shanghai": [
{
"connection": {
"name": "cluster-shanghai-node-1",
"ip": "1.2.3.5",
"rtt": "5ms"
}
}
]
}
}12. /accountz — 账号信息
URL: GET http://nats-server:8222/accountz
参数: ?acc=ACCOUNT_NAME — 查询指定账号的详情
说明: 返回 NATS 账号信息,在多租户(Multi-tenancy)场景中用于查看各账号的资源使用情况和 JetStream 配额。
# 列出所有账号
curl -s http://nats:8222/accountz | jq '.accounts | keys'
# 查看特定账号的 JetStream 使用情况
curl -s "http://nats:8222/accountz?acc=myapp" | jq '{
subscriptions: .subscriptions,
conns: .conns,
js_mem: .jetstream.memory,
js_storage: .jetstream.storage,
js_streams: .jetstream.streams,
js_consumers: .jetstream.consumers
}'13. /statz — 统计信息
URL: GET http://nats-server:8222/statz
说明: 与 /varz 类似,但专注于统计指标,适合 Prometheus 采集前的原始数据确认。
curl -s http://nats:8222/statz | jq '{
connections: .connections,
in_msgs: .in_msgs,
out_msgs: .out_msgs,
in_bytes: .in_bytes,
out_bytes: .out_bytes,
slow_consumers: .slow_consumers
}'14. 常用运维命令集合
以下命令组合了 curl + jq,可直接在 Shell 中执行。
14.1 检查集群整体健康
#!/bin/bash
# cluster-health-check.sh
# 对集群所有节点执行健康检查
NODES=("nats-1:8222" "nats-2:8222" "nats-3:8222")
echo "=== 集群健康检查 $(date '+%Y-%m-%d %H:%M:%S') ==="
for NODE in "${NODES[@]}"; do
echo ""
echo "--- 节点: $NODE ---"
# 1. 基础存活检查
STATUS=$(curl -sf "http://$NODE/healthz" | jq -r '.status' 2>/dev/null || echo "UNREACHABLE")
echo "健康状态: $STATUS"
if [ "$STATUS" = "UNREACHABLE" ]; then
echo "节点无法访问,跳过详情检查"
continue
fi
# 2. 服务器基础信息
curl -s "http://$NODE/varz" | jq '{
version,
uptime,
connections,
slow_consumers,
mem_mb: (.mem / 1048576 | floor)
}'
# 3. JetStream 状态
echo "JetStream 状态:"
curl -s "http://$NODE/jsz" | jq '{
meta_leader: .meta_cluster.leader,
streams: .streams,
consumers: .consumers,
ha_assets: .ha_assets,
api_errors: .api.errors,
storage_gb: (.storage / 1073741824 | . * 10 | round / 10)
}'
# 4. Meta Cluster Raft 状态
echo "Meta Cluster Raft 状态:"
curl -s "http://$NODE/jsz" | jq '.meta_cluster.replicas[] | {name, current, lag, active}'
done14.2 查询所有 Stream 摘要
#!/bin/bash
# list-streams.sh
NODE="${1:-nats-1:8222}"
echo "=== Stream 列表 ==="
curl -s "http://$NODE/jsz?streams=1" | \
jq -r '.account_details[0].stream_detail[] |
[.config.name,
.config.replicas,
.state.messages,
(.state.bytes / 1048576 | floor | tostring) + "MB",
(.cluster.leader // "N/A")] |
@tsv' | \
column -t -s $'\t' -N "NAME,REPLICAS,MESSAGES,STORAGE,LEADER"14.3 查询指定 Stream 的 Consumer 列表
#!/bin/bash
# list-consumers.sh <stream-name>
NODE="${2:-nats-1:8222}"
STREAM="${1:?请指定 Stream 名称}"
echo "=== Stream: $STREAM 的 Consumer 列表 ==="
curl -s "http://$NODE/jsz?consumers=1" | \
jq -r --arg stream "$STREAM" '
.account_details[0].stream_detail[] |
select(.config.name == $stream) |
.consumer_detail[] |
[.name,
(.config.deliver_policy // "all"),
.num_pending,
.num_ack_pending,
.num_redelivered,
(.cluster.leader // "N/A")] |
@tsv' | \
column -t -s $'\t' -N "CONSUMER,POLICY,PENDING,ACK_PENDING,REDELIVERED,LEADER"14.4 查询消费进度(积压分析)
#!/bin/bash
# consumer-lag.sh
NODE="${1:-nats-1:8222}"
echo "=== Consumer 消费积压分析 $(date '+%H:%M:%S') ==="
echo ""
curl -s "http://$NODE/jsz?consumers=1" | \
jq -r '
.account_details[0].stream_detail[] |
.consumer_detail[]? |
[.stream_name,
.name,
.num_pending,
.num_ack_pending,
.num_redelivered,
(if .num_pending > 10000 then "CRITICAL"
elif .num_pending > 1000 then "WARNING"
else "OK" end)] |
@tsv' | \
sort -t$'\t' -k3 -rn | \
column -t -s $'\t' -N "STREAM,CONSUMER,PENDING,ACK_PENDING,REDELIVERED,STATUS"14.5 检查慢消费者
#!/bin/bash
# slow-consumers.sh
NODE="${1:-nats-1:8222}"
echo "=== 慢消费者检测 ==="
SLOW=$(curl -s "http://$NODE/connz?limit=200" | \
jq '[.connections[] | select(.pending_bytes > 0) |
{name, ip, lang, pending_kb: (.pending_bytes / 1024 | floor),
subscriptions}] |
sort_by(-.pending_kb)')
COUNT=$(echo "$SLOW" | jq 'length')
if [ "$COUNT" -eq 0 ]; then
echo "没有慢消费者,一切正常"
else
echo "发现 $COUNT 个慢消费者:"
echo "$SLOW" | jq -r '.[] | [.name, .ip, .lang, (.pending_kb | tostring) + "KB"] | @tsv' | \
column -t -s $'\t' -N "NAME,IP,LANG,PENDING"
fi14.6 实时监控连接数变化
#!/bin/bash
# watch-connections.sh
NODE="${1:-nats-1:8222}"
INTERVAL="${2:-5}"
echo "实时监控连接数(每 ${INTERVAL}s 刷新,Ctrl+C 退出)"
echo ""
PREV_IN=0
PREV_OUT=0
while true; do
DATA=$(curl -s "http://$NODE/varz")
CONNS=$(echo "$DATA" | jq '.connections')
IN=$(echo "$DATA" | jq '.in_msgs')
OUT=$(echo "$DATA" | jq '.out_msgs')
SLOW=$(echo "$DATA" | jq '.slow_consumers')
MEM=$(echo "$DATA" | jq '(.mem / 1048576 | floor)')
IN_RATE=$(( (IN - PREV_IN) / INTERVAL ))
OUT_RATE=$(( (OUT - PREV_OUT) / INTERVAL ))
printf "[%s] 连接数: %-5s 慢消费者: %-3s 内存: %-6sMB 消息/s: in=%-8s out=%-8s\n" \
"$(date '+%H:%M:%S')" "$CONNS" "$SLOW" "$MEM" "$IN_RATE" "$OUT_RATE"
PREV_IN=$IN
PREV_OUT=$OUT
sleep "$INTERVAL"
done14.7 Kubernetes 探针配置完整示例
# nats StatefulSet 探针配置
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nats
spec:
template:
spec:
containers:
- name: nats
image: nats:2.10-alpine
ports:
- containerPort: 4222 # 客户端
- containerPort: 6222 # 集群路由
- containerPort: 8222 # 监控 HTTP
# 存活探针:进程级别,失败则重启容器
livenessProbe:
httpGet:
path: /healthz
port: 8222
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
# 就绪探针:JetStream 本节点就绪后才接受流量
readinessProbe:
httpGet:
path: /healthz?js-server-only=true
port: 8222
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# 启动探针:给 JetStream 足够时间初始化(大量数据时恢复较慢)
startupProbe:
httpGet:
path: /healthz
port: 8222
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 5
failureThreshold: 30 # 最多等待 30*5=150s15. 告警指标建议
15.1 使用 nats-prometheus-exporter
# 安装
go install github.com/nats-io/prometheus-nats-exporter@latest
# 启动(采集所有端点)
prometheus-nats-exporter \
-varz -jsz -connz -routez \
-addr 0.0.0.0 \
-port 7777 \
http://nats-1:8222 http://nats-2:8222 http://nats-3:822215.2 核心告警规则(Prometheus AlertManager)
# nats-alerts.yaml
groups:
- name: nats_critical
rules:
# 节点不可达
- alert: NATSNodeDown
expr: up{job="nats"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "NATS 节点不可达: {{ $labels.instance }}"
description: "NATS 节点已超过 1 分钟无法访问"
# 慢消费者出现
- alert: NATSSlowConsumers
expr: gnatsd_varz_slow_consumers > 0
for: 2m
labels:
severity: warning
annotations:
summary: "NATS 存在慢消费者: {{ $value }} 个"
description: "存在积压未消费消息的连接,可能导致消息堆积"
# JetStream 存储使用率过高
- alert: JetStreamStorageHigh
expr: (gnatsd_jsz_storage / gnatsd_jsz_config_max_storage) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "JetStream 存储使用率 {{ $value | humanizePercentage }}"
description: "JetStream 磁盘使用超过 80%,请及时清理或扩容"
- alert: JetStreamStorageCritical
expr: (gnatsd_jsz_storage / gnatsd_jsz_config_max_storage) * 100 > 95
for: 2m
labels:
severity: critical
annotations:
summary: "JetStream 存储紧急: {{ $value | humanizePercentage }}"
# JetStream API 错误率
- alert: JetStreamAPIErrors
expr: increase(gnatsd_jsz_api_errors[5m]) > 10
for: 2m
labels:
severity: warning
annotations:
summary: "JetStream API 错误数增加: {{ $value }} 次/5min"
# Consumer 消费积压
- alert: ConsumerLagHigh
expr: nats_consumer_num_pending > 10000
for: 5m
labels:
severity: warning
annotations:
summary: "Consumer {{ $labels.consumer_name }} 积压 {{ $value }} 条消息"
- alert: ConsumerLagCritical
expr: nats_consumer_num_pending > 100000
for: 2m
labels:
severity: critical
annotations:
summary: "Consumer {{ $labels.consumer_name }} 严重积压 {{ $value }} 条"
# Meta Cluster 副本落后
- alert: JetStreamMetaRaftLag
expr: nats_meta_cluster_replica_lag > 1000
for: 2m
labels:
severity: warning
annotations:
summary: "JetStream Meta Raft 副本落后 {{ $value }} 条日志"
# 连接数接近上限
- alert: NATSConnectionsHigh
expr: (gnatsd_varz_connections / gnatsd_varz_max_connections) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "NATS 连接数使用率 {{ $value | humanizePercentage }}"
# 路由数量异常(应等于集群节点数 - 1)
- alert: NATSRoutesMissing
expr: gnatsd_routez_num_routes < 2
for: 3m
labels:
severity: critical
annotations:
summary: "NATS 集群路由丢失,当前只有 {{ $value }} 条路由(期望 2)"15.3 Grafana Dashboard 推荐指标
| 面板名称 | 指标 | 说明 |
|---|---|---|
| 连接数趋势 | gnatsd_varz_connections | 监控连接数变化 |
| 消息吞吐 | rate(gnatsd_varz_in_msgs[1m]) | 每秒消息接收数 |
| 内存使用 | gnatsd_varz_mem | 内存趋势 |
| JetStream 存储 | gnatsd_jsz_storage | 磁盘使用趋势 |
| Consumer 积压 | nats_consumer_num_pending | 按 Consumer 分组 |
| 慢消费者数 | gnatsd_varz_slow_consumers | 应始终为 0 |
| Raft 副本落后 | nats_stream_cluster_replica_lag | 应始终为 0 |
| Meta Leader | nats_meta_cluster_leader | 监控 Leader 切换 |
| API 错误率 | rate(gnatsd_jsz_api_errors[5m]) | 应接近 0 |
15.4 监控最佳实践
1. 采集频率:建议 15s 采集一次 /varz,60s 采集一次 /jsz?consumers=1(后者数据量大)
2. 关键 SLI 指标:
- 可用性:节点存活率 >= 99.9%
- 消费延迟:Consumer num_pending < 10000(正常业务流量)
- 持久化延迟:Publish 到 PubAck 的 p99 < 50ms
3. 数据保留:Prometheus 保留 15 天,用于趋势分析和容量规划
4. 告警分级:
- CRITICAL:立即响应(页面通知),影响服务可用性
- WARNING:工作时间处理,影响性能但不影响可用性
5. 监控端点安全:生产环境应限制 8222 端口只对内网访问,避免暴露业务信息