基于Prometheus与Grafana自定义Consul监控面板实践 如果只是要“能看出 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.hcltelemetry { 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?formatprometheus | head -20如果看到# HELP consul_raft_leader这类输出就说明已经通了。注意?formatprometheus这个参数必须带否则默认输出的是 JSON。2.2 Prometheus 抓取配置在 Prometheus 的prometheus.yml里新增一个 jobscrape_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里必须带formatprometheus。如果不带Consul 默认返回 JSONPrometheus 会报解析错误面板就什么都查不到。抓取目标建议写所有 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 里定义几个变量变量名定义方式用途nodelabel_values(consul_health_node_status, node)筛选单个节点dclabel_values(consul_serf_lan_members, dc)筛选数据中心statuslabel_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.formatprometheus必须加上否则抓回来是 JSONGrafana 里看到的标签会非常奇怪。5.2 面板数据不对现象集群实际有 5 个节点但面板显示 10 个。这个大概率是节点指标被重复上报了。比如每个 Consul agent 都会暴露本地视角的节点信息如果有多个 agent 上报同一批节点就会出现重复计数。解决方式就是按节点去重count(distinct(consul_health_node_status{statuspassing}))如果指标里带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{statuscritical}) / sum(consul_health_node_status) ) * 100超过百分之几就触发时间窗口同样设置 5 分钟。这个告警适合在服务规模大的集群里用比直接对单节点告警更不容易误报。告警通知我一般接到企业微信群或飞书机器人。Grafana 自带的通知渠道里有 Webhook只需要配置好回调地址即可。如果业务方平时不看 Grafana可以把告警直接推到即时通讯的群里。6.2 后续还能怎么扩展这套自定义面板只是第一步。跑稳定后我建议继续做三件事把面板和告警规则代码化。用 Terraform 管理 Grafana dashboard 和数据源或者把 JSON 保存到 Git 仓库让变更留痕避免所有人都在生产 Grafana 上手动改来改去。把 Consul 指标和业务日志联动。只看指标能发现异常但往往不知道元凶。我会把节点异常时间点对齐到业务日志的时间线在排障时能省很多时间。把 Consul 的自动恢复流程纳入监控闭环。比如节点掉线时自动触发重启脚本或者通知后端系统重新拉取服务列表实现一定程度的自愈。个人实践下来监控体系和业务一样都需要迭代。一开始你只需要看节点和 leader服务规模大了KV 和健康状态指标就不得不看再后来你可能还需要给不同业务线划分不同的 dashboard 页面。所以不要追求一步到位先把第一版跑起来然后在真实故障里不断调整阈值和面板结构最终会变成一套非常贴合你们业务的监控系统。