如果只是要“能看出 Consul 在跑”,随便拉一个现成面板就够了;但如果你负责的是一个正在支撑业务的 Consul 集群,一整天最关心的其实是那几个问题:leader 有没有频繁切换?节点健康检查是不是开始飘红?KV 读写量有没有异常上涨?服务注册与注销的频率是不是不对劲?这些需求,模板面板通常给不到,而且各家 Consul 的指标命名、标签习惯、服务场景又不一样,唯一靠谱的路线,就是基于自己的业务逻辑去定制一套 Grafana 面板。
我这次要分享的就是这样一个实践:使用自定义 Grafana 面板监控 Consul。内容会覆盖指标采集链路怎么搭、核心面板怎么设计、PromQL 怎么写、模板变量和告警怎么配,以及我在真实环境里踩过的坑。适合正在用 Consul 做服务注册发现、又在 Grafana 里想搭一套贴合自己业务监控的人参考。
1. 方案设计:为什么是“Prometheus + 自定义 Grafana 面板”
先明确监控对象。Consul 本身有自带的 Web UI 和 API,但那些更适合临时排查问题,不适合长期盯盘。你需要的是一个能存历史数据、能画曲线、能配置告警的统一监控平台。当前主流组合就是 Prometheus 负责采集和存储时序数据,Grafana 负责展示和告警。Consul 正好原生暴露 Prometheus 格式的指标接口,所以整个链路是顺理成章的:Consul agent 输出指标,Prometheus 定期抓取,Grafana 从 Prometheus 数据源查询并绘制仪表盘。
1.1 为什么不用现成模板
一开始我也直接从面板市场导入过现成的“Consul 监控”开源面板。导入之后发现几个问题:
- 模板里的面板要么太多、很冗余,要么太少、关键维度缺失。我在意的指标没在模板里,我不关心的指标倒是占了一大块。
- 指标版本对不上。不同 Consul 版本的指标名、标签结构可能不同,空查的图表能堆出半屏。
- 模板无法适配业务语义。比如我团队里服务健康阈值是按“连续 5 分钟无成功注册”来告警,模板里写的是固定 15 分钟区间,没法直接反映真实问题。
所以“自定义”不是炫技,而是把监控口径拉回业务现场的必选项。
1.2 指标体系的选型思路
Consul 的指标非常多,我最初也试图全部展示,结果面板又乱又慢。后来我按以下维度做了取舍:
| 维度 | 对应指标类型 | 监控目的 |
|---|---|---|
| 集群全局状态 | serf 节点数、raft leader | 快速判断集群是否“活着” |
| 服务健康 | health node/service status | 发现节点或服务的不健康状态 |
| 集群稳定性 | raft commit、apply 速率 | 发现 leader 切换和事务堆积 |
| 资源消耗 | runtime alloc、heap objects | 判断 Consul 进程是否有内存压力 |
| 业务操作量 | kv set、catalog register | 感知业务对 Consul 的使用强度 |
这五个维度基本覆盖了“集群自身状态”和“业务使用情况”两端。面板布局我也按这个维度来排,而不是简单地堆图表。
1.3 自定义面板的信息架构
我最终的 dashboard 分四行:
- 第一行:集群总览。显示节点数、Raft Leader 数量、是否有 leader、当前时间窗口内 Raft 提交速率。
- 第二行:服务健康。显示通过、警告、宕机节点数,以及服务注册与注销的速率。
- 第三行:Raft 稳定性。显示 peers、commit 次数、apply 速率、leader 切换趋势。
- 第四行:资源消耗与 KV 操作。显示内存分配、堆对象数、KV 写入速率等。
这样的布局是为了让“事故发生时第一眼能看到什么”成为主线。有人在跑服务,有人在做域控,把不同关注点分离开,也避免面面俱到反而什么都看不清的问题。
2. 环境准备:从 Consul 指标采集到 Grafana 数据源
这步没有太多花样,但有几个关键配置很容易忽略。
2.1 打开 Consul 的 Prometheus 指标开关
Consul 默认情况下不会把 Prometheus 格式指标原样输出,需要显式开启。修改 Consul 的配置文件(比如/etc/consul/consul.hcl):
telemetry { prometheus_retention_time = "24h" disable_hostname = true }解释一下:
prometheus_retention_time表示 Prometheus 格式指标在 Consul 端的保留时间。这个值不是必须设得很大,因为 Prometheus 抓走后会自己存很久,但设置为24h能防止 Prometheus 在抓取间隙重启时丢失数据。disable_hostname = true是用来避免指标名里带上主机名前缀的,这样 Grafana 里查询指标时名字能保持一致,否则可能变成consul-server-1_consul_runtime_alloc_bytes这种格式,查询会很痛苦。
修改后重启 Consul 进程。验证是否生效可以直接 curl 一下:
curl -s http://127.0.0.1:8500/v1/agent/metrics?format=prometheus | head -20如果看到# HELP consul_raft_leader这类输出,就说明已经通了。注意?format=prometheus这个参数必须带,否则默认输出的是 JSON。
2.2 Prometheus 抓取配置
在 Prometheus 的prometheus.yml里新增一个 job:
scrape_configs: - job_name: consul honor_labels: true metrics_path: /v1/agent/metrics params: format: ["prometheus"] static_configs: - targets: - 10.0.0.11:8500 - 10.0.0.12:8500 - 10.0.0.13:8500这里有两个重点。
metrics_path指向/v1/agent/metrics,而不是常见的/metrics。因为 Consul 的指标是挂在 HTTP API 路径上的,所以 Prometheus 抓取路径必须对齐。
params里必须带format=prometheus。如果不带,Consul 默认返回 JSON,Prometheus 会报解析错误,面板就什么都查不到。
抓取目标建议写所有 Consul agent 的地址,包括 server 和 client。因为有些指标是每 agent 独立的,比如节点健康状态,只在对应 agent 上暴露。
如果你的 Consul 启用了 ACL,还要在抓取配置里带上 token,否则/v1/agent/metrics会被拒绝。一般是在params里加token,或者在 Prometheus 的basic_auth配置里处理。
2.3 Grafana 数据源配置
在 Grafana 里添加 Prometheus 数据源时,URL 填 Prometheus 服务地址,比如http://prometheus-server:9090。如果 Grafana 和 Prometheus 部署在不同网段,注意访问方式要选择 Server 而不是 Browser,否则浏览器端访问不到内网地址,面板数据会一直加载不出来。
配置好后,可以先在 Explore 页面验证一下能否查到consul_raft_leader这个指标。如果能搜到,说明链路已经通了。
3. 核心面板实现:关键指标与 PromQL 逐面板拆解
这是我花时间最多的地方。PromQL 的写法直接决定了面板是“能看”还是“好用”。
3.1 集群总览行
我用了四个纯数字面板:
- 在线节点数:
sum(consul_serf_lan_members) - Raft Leader 个数:
count(consul_raft_leader == 1) - 当前是否有主节点:可以用这个查询配合阈值处理
- Raft 提交速率:
rate(consul_raft_commit[5m])
为什么consul_serf_lan_members用sum?因为同一个节点可能会被多个 agent 上报,直接展示原始 series 会看到好几条曲线。用sum聚合后,得到的是集群内实际成员的总数。如果你的集群有多个数据中心,可能还得按dc标签分组:
sum by (dc) (consul_serf_lan_members)
还有一个容易踩坑的点:consul_raft_leader这个指标在非 leader 节点上是 0,在 leader 节点上是 1。所以领路唯一判定我一般写作count(consul_raft_leader == 1),正常情况下结果应该是 1;如果结果是 0,说明集群里没有可用的 leader,那是很严重的异常。
3.2 服务健康与节点状态
Consul 的健康检查状态是分类的,对应的 Prometheus 指标大致是consul_health_node_status和consul_health_service_status,都带一个status标签,值可能是passing、warning、critical、maintenance。
统计不健康节点数:
sum(consul_health_node_status{status!="passing"})统计各类状态分布,我一般用:
sum by (status) (consul_health_node_status)这个查询会按状态画出多条线,一眼就能看出颜色的分布。如果你的 Consul 指标命名不完全一样,可以先用label_values()或者我们 2.3 节的 Explore 方式确认一下标签名。
服务注册注销速率:
- 注册速率:
rate(consul_catalog_register[5m]) - 注销速率:
rate(consul_catalog_deregister[5m])
这两个指标能从业务角度反映服务生命周期变化。比如某个瞬间注册速率突然飙升,伴随大量注销,多半是有实例在频繁重启,或者发布系统在批量部署。
3.3 Raft 稳定性与事务量
Consul 用 Raft 协议做一致性。监控 Raft 的关键是看 leader 是否稳定、日志提交是否通畅。
关键查询:
# Raft 提交计数 rate(consul_raft_apply[5m]) # Peers 数量 consul_raft_peers # Leader 切换趋势 changes(consul_raft_leader[5m])changes()这个函数很好用,它返回指标在时间窗口内发生变化的次数。如果changes(consul_raft_leader[5m])大于 0,说明过去 5 分钟内 leader 发生了切换。偶尔一次可能还好,如果频繁出现,就要警惕网络分区、节点资源不足、或某些节点的心跳异常。
我还习惯给“Leader 当前数”加一条阈值线,当长时间为 0 时告警。具体告警逻辑放在第 6 小节说。
3.4 资源消耗与 KV 操作
Consul 运行本身吃内存,尤其是当服务数量、KV 条目数量增长后。我常看这几个指标:
# 内存分配量 consul_runtime_alloc_bytes # 堆对象数 consul_runtime_heap_objects # KV 写入速率 rate(consul_fsm_consul_kv_set[5m])在生产环境,我习惯把consul_runtime_alloc_bytes换算成 MB 展示,方便值班同学判断。可以在 Grafana 面板的 Standard options 里设置 Unit 为bytes (SI),或者直接用consul_runtime_alloc_bytes / 1024 / 1024转为 MB。
KV 写入速率是我个人比较看重的一个指标。很多业务系统会把配置、分布式锁、租约信息存到 Consul KV,如果 KV 写入速率突然暴涨,往往意味着某个服务在疯狂写配置,或者锁竞争异常。这类问题不一定影响 Consul 本身,但对业务影响很大,监控上必须能看见。
4. 自定义面板的进阶玩法:模板变量与多集群复用
面板在单机 Consul 集群上跑通后,下一步就是让它能在多节点、多机房、多集群场景下复用。模板变量是这里的关键。
4.1 模板变量搭建
我一般会在 Grafana dashboard 的 Settings 里定义几个变量:
| 变量名 | 定义方式 | 用途 |
|---|---|---|
node | label_values(consul_health_node_status, node) | 筛选单个节点 |
dc | label_values(consul_serf_lan_members, dc) | 筛选数据中心 |
status | label_values(consul_health_node_status, status) | 筛选健康状态 |
之后每个面板的查询都能用变量来约束范围。例如,只看特定数据中心的节点:
sum by (node) (consul_health_node_status{dc="$dc"})这里要注意:变量值依赖指标里的标签,如果指标本身没有dc标签,那就定义不出来。遇到这种情况,可以先到 Prometheus 里看一下该指标的标签集合,再决定变量怎么建。
还有一个技巧:变量可以设置为“All”。比如status变量允许选全部状态,那么查询中最好写成{status=~"$status"},而不是{status="$status"}。因为 Grafana 在变量选择为All时会注入一个正则匹配串,=~才能正确匹配。
4.2 面板 JSON 的结构与复用技巧
如果你不想靠鼠标重复建面板,也可以直接编辑 dashboard 的 JSON 文件来实现批量复用。Grafana 的 dashboard 本质是一个 JSON 文件,里面有panels数组,每个 panel 是一个对象。举个例子,一个简单的 Raft Leader 状态面板的 JSON 长这样:
{ "type": "stat", "title": "Raft Leader", "datasource": { "type": "prometheus", "uid": "your-prometheus-datasource-uid" }, "fieldConfig": { "defaults": { "thresholds": { "steps": [ { "color": "red", "value": null }, { "color": "green", "value": 1 } ] } } }, "targets": [ { "expr": "count(consul_raft_leader == 1)", "legendFormat": "leader" } ], "gridPos": { "h": 4, "w": 4, "x": 0, "y": 0 } }把这样的 JSON 片段插到 dashboard JSON 的panels数组里,再调整gridPos就能快速复制面板。对多集群场景,还可以把 dashboard JSON 保存到 git 里,用 CI 统一部署。
不建议把同一个 dashboard 复制到多个 Grafana,更推荐用一个带变量的 dashboard 再配合不同的数据源或标签。比如在 Prometheus 中给不同集群打上/cluster标签,然后在面板里用$cluster变量过滤,这样维护一套 JSON 就够了。
4.3 自定义面板的细节调优
面板不是“数据能画出来”就行了。我做以下几个细节调优:
- 单位设置:内存类指标设置为
bytes,速率类指标设置为cps,百分比类指标设置为percent,避免值班同学看一串原始数字还要心算。 - 图例格式化:查询时尽量用
legendFormat把图例写成有含义的名字,比如{{dc}} / {{node}} / {{status}},避免默认的Series 1、Series 2。 - 时间区间:一些瞬时状态面板(如“当前节点数”)建议设置
instant查询。Grafana 里把查询的Format选为Instant,面板上就只显示当前值,不会因为时间窗口变化而出现误导性的历史平均值。 - 阈值线:在 Stat 面板里加阈值线和颜色转变,例如节点数低于 3 就变红,这样值班人员能在远距离一眼发现问题。
5. 真实环境里的坑:问题排查与经验
这块内容基本是我在落地这套监控时踩过的坑汇总,建议先收藏。
5.1 指标抓不到
现象:Grafana 面板全空,或者部分 Consul 节点没有数据。
排查步骤:
- 先看 Prometheus 的 Targets 页面,确认抓取目标是不是 UP。如果状态是 DOWN,检查网络连通性、ACL Token、端口。
- 如果状态是 UP 但面板空,先用 Explore 查一下指标名是否存在。Consul 版本升级后指标名称可能变化,比如某些老版本叫
consul.raft.apply,新版本叫consul_raft_apply,这种差异很容易导致查询为空。 - 确认抓取路径和参数。我在 2.2 里写的
params.format=prometheus必须加上,否则抓回来是 JSON,Grafana 里看到的标签会非常奇怪。
5.2 面板数据不对
现象:集群实际有 5 个节点,但面板显示 10 个。
这个大概率是节点指标被重复上报了。比如每个 Consul agent 都会暴露本地视角的节点信息,如果有多个 agent 上报同一批节点,就会出现重复计数。解决方式就是按节点去重:
count(distinct(consul_health_node_status{status="passing"}))如果指标里带instance标签,也可以按instance区分开看。不要图省事直接sum,一定要先想清楚指标是全局的还是节点级的。
5.3 告警抖动与基数问题
这是我认为最影响使用体验的两个问题。
告警抖动。如果直接对queue_consul_raft_apply[1m]设一个超过阈值的告警,可能在高峰期频繁触发。我的做法是在 Prometheus 的告警规则里加上持续时间,例如 5 分钟内持续大于阈值才告警,同时使用 rate 而不是瞬时值,减小抖动影响。
高基数。Consul 的指标如果带上了节点、服务、状态、数据中心等大量标签,series 数量会膨胀得很厉害。特别是服务数量多、节点数量大的时候,一个consul_health_service_status就能生成几千条序列。我的建议是面板查询尽量先用sum by聚合,减少 Grafana 渲染压力,同时在 Prometheus 端适当做metric_relabel_configs过滤掉不用的标签。
还有一个容易忽略的坑:面板“空闲”时看起来一切正常,但一旦你拖动时间范围回查很久以前的数据,Grafana 可能要花很长时间。原因是查询粒度太细。我习惯在时间范围超过 7 天时,把查询选项里的Interval调大,比如拉到 5m 甚至 1h,让数据点密度降低,图表也能快速加载。
6. 告警规则与后续迭代建议
看板解决了“看”,告警才解决“管”。我一开始只做面板,结果出问题还是靠业务方打电话才知道,很被动。
6.1 从面板出发配告警
在 Grafana 新版里,可以直接在面板的 Alert 页签里创建规则。比如“Raft 节点丢失”的告警:
count(consul_raft_leader == 1) < 1评价周期可以设置为5m,这样当集群 5 分钟没有主节点时才告警,避免节点重启导致临时抖动。
另一个我常用的告警是“节点健康状态非 passing 比例超过阈值”:
( sum(consul_health_node_status{status="critical"}) / sum(consul_health_node_status) ) * 100超过百分之几就触发,时间窗口同样设置 5 分钟。这个告警适合在服务规模大的集群里用,比直接对单节点告警更不容易误报。
告警通知我一般接到企业微信群或飞书机器人。Grafana 自带的通知渠道里有 Webhook,只需要配置好回调地址即可。如果业务方平时不看 Grafana,可以把告警直接推到即时通讯的群里。
6.2 后续还能怎么扩展
这套自定义面板只是第一步。跑稳定后,我建议继续做三件事:
- 把面板和告警规则代码化。用 Terraform 管理 Grafana dashboard 和数据源,或者把 JSON 保存到 Git 仓库,让变更留痕,避免所有人都在生产 Grafana 上手动改来改去。
- 把 Consul 指标和业务日志联动。只看指标能发现异常,但往往不知道元凶。我会把节点异常时间点对齐到业务日志的时间线,在排障时能省很多时间。
- 把 Consul 的自动恢复流程纳入监控闭环。比如节点掉线时,自动触发重启脚本或者通知后端系统重新拉取服务列表,实现一定程度的自愈。
个人实践下来,监控体系和业务一样,都需要迭代。一开始你只需要看节点和 leader,服务规模大了,KV 和健康状态指标就不得不看,再后来你可能还需要给不同业务线划分不同的 dashboard 页面。所以不要追求一步到位,先把第一版跑起来,然后在真实故障里不断调整阈值和面板结构,最终会变成一套非常贴合你们业务的监控系统。