ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Grafana Dashboard变量设计实战:一套面板复用多环境监控

Grafana Dashboard变量设计实战:一套面板复用多环境监控

做监控这行,天天打交道最多的界面就是Grafana Dashboard。刚开始用的时候,拉几个开源模板把node_exporter、MySQL exporter的指标一贴,觉得挺好看,数据也是那么回事。真正开始做自定义监控面板,是在某公司接手一套多机房多应用的业务系统之后——几十台机器、十几个应用、四五个机房,如果每个应用都单独画一套面板,光维护就够喝一壶的。后来把整套体系的思路捋顺了,核心就两件事:一个是自定义面板怎么画才够清楚,另一个是变量(Variables)怎么设计才能让一套面板打通所有场景。

这篇内容适合正在从“看模板”转向“写面板”的运维、SRE、后端开发,尤其适合想用一套Dashboard模板复用给多个应用、多个环境的人。我会把这些年在Grafana上踩过的坑、实践过的变量用法、面板设计逻辑都梳理出来,尽量把“为什么这么干”也讲清楚。

1. 为什么监控面板要定制,而不是套模板

1.1 从“能用”到“好用”:自定义面板解决了什么

套模板本身没错,开源模板作为起点是很好的参考。但大部分模板都是从特定环境出发设计的,到了你的业务里,标签名不一样、指标语义不一样、关注的维度不一样,模板就成了一个“能显示但不解决问题的装饰画”。自定义面板的核心价值,是让监控界面回到问题本身:出故障的时候,打开面板,三秒内能定位到是哪个实例、哪个应用、哪个环节出了问题。

我见过不少团队,面板数量几十个,但真正排障时翻来翻去还是那几个默认的。问题不在于面板少,而在于面板上的信息没有跟业务维度建立对应关系。比如CPU、内存、磁盘这种基础监控,机器多了以后,你必须能按机房、按应用、按角色过滤,才能在大盘上快速收敛问题范围。这种按维度过滤的能力,就是变量。

另一个容易被忽略的点:自定义面板的过程,其实就是把团队的监控标准“写”下来。同样一个“请求量”,不同人写出的PromQL可能差别很大。当面板成为团队共享的资产,指标口径就统一了,后面做告警、做周报、做容量评估都建立在同一套数据语言上,省掉大量沟通成本。

1.2 什么时候需要用到变量

变量在Grafana里听起来是个小功能,实际上它是Dashboard能不能复用的分水岭。没有变量的时候,一个面板只能盯着一组固定的对象;加了变量之后,面板变成了“模板”,对象的切换由下拉框、输入框在渲染时完成。

用个生活化的类比:变量就像洗衣机面板上的程序选择旋钮。你选“棉麻”“化纤”“羊毛”,洗衣机的进水量、转速、程序都变了,但机器本身还是那一台。Grafana的变量也是一样,你在下拉框里选一个机房,面板上的所有查询都会把机房的标签值替换进去,重新渲染出一整屏针对该机房的指标。

具体到使用场景:

  • 多环境切换:同一个系统有dev、test、prod,变量一选就能看对应环境的指标。
  • 多应用复用:一套“应用健康度”面板,通过变量在十几个微服务之间切换。
  • 同屏对比:多值变量配合正则匹配,可以把多个实例画在同一张图上对比。
  • 模板导出分享:变量定义在Dashboard的JSON里,面板跟数据源分离,换环境导入后只需重新选数据源。

如果你只是一个人自己看某一个服务的监控,变量可能没啥感觉;但只要你的监控对象超过五台机器、两三个应用,变量就是必须的东西。

2. 选型与方案设计:面板类型、数据源与指标模型

2.1 面板类型怎么选:先问“这个面板要回答什么问题”

Grafana的面板类型远不止时间序列图一个。我见过很多人的Dashboard,清一色全是折线图,一个面板里塞七八条线,颜色都分不清。这其实是选型偷懒了。

按我的经验,选面板之前先问一句:这个面板要回答什么问题?

  • 如果问题是“最近一小时请求量走势怎么样”,用Time series折线图最合适,重点看趋势和异常拐点。
  • 如果问题是“现在服务是不是快挂了”,用Stat(单个数值)或者Gauge(仪表盘)更直观,直接给一个当前值加红黄绿阈值色。
  • 如果问题是“过去一天里哪些实例发生过异常”,用State timeline(状态历史)比时间序列图清晰得多,横条按时间着色。
  • 如果问题是“各应用当前请求量的排序、错误率排名”,用Table或Bar chart更合适,信息密度高、适合导出。
  • 如果数据里有日志字段,可以加Logs面板,或者直接跟Explore联动。

记住一个原则:一块面板只回答一个问题。问题多了就拆成多块,宁可多用几行grid空间,也不要在一个图里堆五颜六色的曲线。另一个实操点是:图例多的时候,给每一条线打上清晰的display name,不要默认显示指标名,否则排障时你根本分不清谁是谁。

2.2 数据源接入与指标查询设计:先有指标模型,再有面板

面板看起来是画图,本质上是查数。Grafana支持的数据源很多,Prometheus、InfluxDB、Elasticsearch、MySQL、Loki、Jaeger都有对应的插件。选型上的建议是:时序指标用Prometheus或InfluxDB,日志用Loki或ES,链路用Jaeger或Tempo,不要想着在一种数据源里装下所有东西,Grafana本身只是聚合视图。

指标查询设计比面板样式重要得多。很多新手直接对着指标名就写查询,结果面板上出现一堆“NaN”或者数值大得离谱。我建议在写面板之前,先按监控方法论把指标列清楚:

  • 系统资源类:CPU使用率、内存使用率、磁盘使用率、网络带宽、负载、文件描述符。
  • 应用性能类:请求量(QPS)、错误率、延迟(P50/P95/P99)、线程池空闲、连接池占用。
  • 业务结果类:下单量、支付成功率、订单状态分布,这类经常需要从应用埋点或业务数据库采集,不能只靠exporter。

以Prometheus为例,一个基础的CPU使用率查询是这样:

100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

这里的关键点有两个:一是用rate而不是直接查counter字段,二是用avg by (instance)把维度收敛到实例粒度。很多人直接把node_cpu_seconds_total画出来,得到的是持续累加的秒数,根本不是使用率,这就是没理解指标语义。

单位规范化也属于指标设计的一部分。面板上的单位要跟指标的实际含义对应:网络流量用bytes还是bits,要统一;内存数值如果原始指标是bytes,面板单位就选bytes或自动换算成GB;百分比指标就选percent。单位配错了,面板上的数字会非常误导人,比如0.5%显示成0.5还不带符号,值班的人根本不知道是不是异常。

3. 变量使用技巧:从入门到模板化

3.1 变量基础类型:各自适用的场景

Grafana的变量可以在Dashboard Settings -> Variables里配置,常见类型有Query、Custom、Constant、Interval、Datasource、Textbox。

Query变量是最常用的,它的值来源于数据源查询。比如我有一个node_uname_info指标,里面带有nodename标签,我就可以定义变量instance,查询写法是:

label_values(node_uname_info, nodename)

这会把所有nodename标签值列成下拉选项。还有一种写法是:

label_values(up{job="$job"}, instance)

这种在查询里引用其他变量的写法,就是级联下拉的基础:先选job,再根据job过滤出可用的instance列表。

Custom变量的场景是选项固定不变,比如地区、环境、团队:

  • 类型Custom,值填:dev,test,prod,或带分组的写法:dev :: 业务开发环境,test :: 测试环境。

Constant变量是一个固定值,通常用在某个面板的所有查询里都引用同一个参数,比如集群名称。Textbox变量则是让使用者手动输入字符串,适合临时过滤,比如输入某个订单号或IP段前缀。

这里有一个很实用的建议:变量名不要乱取,统一用小写英文,不要带空格。因为变量引用方式是$变量名,如果变量名叫“Node Name”,写查询时容易出错且难读。我一般习惯用app、dc、instance、job这样的短名字。

3.2 联动过滤与正则:选项跟着上一步走

面板变量之间如果完全独立,就会出现一个乱象:选了机房A,实例列表里却有机房B的机器,画图时数据对不上。解决方式是让下一级变量基于上一级变量的值去查询。

实现方法就是在Query变量的查询里引用上游变量,比如:

label_values(node_uname_info{dc="$dc"}, nodename)

这样实例下拉框里就只会出现所选数据中心的机器。

在定义变量时还有一个“Regex”字段,这是很多人的盲区。它不是用来在数据源里做全文检索的,而是对查询结果做的正则过滤。比如我只需要名称以web开头的实例,可以写:

/^web.*/

注意这里的写法是前后带斜杠的字符串。一个常见的坑是:忘了写锚点^和.*,导致匹配到意料之外的值。另一种用法是用正则去掉后缀,比如把/_(.*)/替换成$1,可以让下拉框只显示去掉前缀后的可读名称。

正则过滤适合什么场景?比如你的标签值里有prod-node-01和prod-node-02,也有dev-node-01,但某个面板只想关注生产环境,就通过正则把dev的选项滤掉。不过要提醒一点:正则过滤只是把下拉选项过滤掉,查询语句里的数据源如果不带过滤条件,画出来的图可能还是会包含dev的数据,最终过滤靠的是查询里的$instance =~ "$var"这类写法,而不是只靠变量下拉框。

3.3 内置变量与模板化复用:让面板自动适应时间范围和步长

Grafana还提供几个内置变量,我最常用的有三个:

  • $__from和$__to:代表当前时间范围的起点和终点,单位毫秒,通常在写SQL类数据源或需要精确时间戳时用。
  • $__interval:代表每条数据点之间的时间间隔,Grafana会根据时间范围和面板宽度自动计算。
  • $__range:整个时间范围的秒数。

以Prometheus为例,如果我们按主机聚合CPU5分钟平均,可以像这样写:

avg(rate(node_cpu_seconds_total{mode="idle",instance=~"$instance"}[$__interval])) by (instance)

用$__interval做rate窗口,面板会自动适配不同的时间范围,不会因为时间范围拉长导致图像变糙。

模板化复用的核心思路是:把面板标题、描述、查询里所有可能变化的部分都抽成变量。比如面板标题可以写CPU使用率 - $instance,这样切换实例时标题跟着变。然后导出Dashboard JSON,在另一个环境导入时,只需要改数据源和变量定义,整套面板就能复用。

这里给一个版本管理的建议:Dashboard JSON要纳入版本控制,文件很小,diff很方便。很多团队的面板改来改去没人知道改了什么,把JSON存到Git里之后,面板本身的变更历史也是一清二楚的。

4. 实操过程:从零搭建一套模板化监控面板

4.1 场景定义与数据准备

我拿一个实际做过的场景来演示。某公司有两个机房(dc-a、dc-b),跑了七八个应用,每个应用有多台实例。我希望能有一套“应用总览”面板,通过顶部下拉框选择机房、应用、实例,就可以切换视角,并且同一个面板复制到测试环境直接能用。

动手之前,先检查数据源里有没有携带足够的标签。Prometheus的指标里,application这个标签经常要应用侧埋点才能带出来,exporter本身不会有。所以当时我们第一步是跟开发约定,所有业务指标必须带application、dc、instance三个标签,这样变量才有据可依。这个约定写在监控规范文档里,后面所有面板都统一引用。

先验证标签值能不能查到,在Explore里执行:

label_values(application)

如果返回空,说明标签还没产生,那就变成查exporter的标签名而不是业务标签,整个面板的维度就从根上错了。这一步一定要在画面板之前确认。

4.2 从变量到面板的完整配置

新建Dashboard之后,先配置变量,顺序是从大范围到小范围:

  1. 定义dc,Query变量:label_values(application, dc)
  2. 定义app,Query变量并引用dc:label_values(application{dc="$dc"}, application)
  3. 定义instance,同样联动:label_values(application{dc="$dc",application="$app"}, instance),并打开Multi-value选项,启用Include All option,让下拉框支持多选和全选。

接着添加一个时间序列面板,查询怎么写?我以“每秒请求量”为例:

sum(rate(http_requests_total{application="$app", instance=~"$instance"}[5m]))

这里为什么instance用=~而application用=?因为instance变量设置了多值和All,多选时传递的值是类似"inst-a|inst-b"的正则字符串,必须用=~才能匹配;而application单选用等号。如果你把多选变量用=去匹配,数据必然查不出来,这是新手最常踩的坑。

再配置面板的Legend和Unit。Legend格式化模板写{{instance}},单位选requests/s。然后在面板标题里写$app 请求量,这样切换应用时标题自动变化,截图给别人看也不会误解。

另一些常用的查询直接抄过来:

  • CPU使用率(按实例):
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle", instance=~"$instance"}[$__interval])) * 100)
  • 请求错误率:
sum(rate(http_requests_total{application="$app", instance=~"$instance", status=~"5.."}[5m])) / sum(rate(http_requests_total{application="$app", instance=~"$instance"}[5m]))
  • 内存使用率(基于node_exporter):
(1 - (node_memory_MemAvailable_bytes{instance=~"$instance"} / node_memory_MemTotal_bytes{instance=~"$instance"})) * 100

阈值和告警一并在这步配置。Grafana的Threshold可以在面板设置里给不同的数值区间上色,比如请求错误率超过1%变红,超过0.5%变黄。告警规则每个面板单独配,也可以直接跳到Alerting里统一管理,建议至少把错误率和CPU使用率配上告警。

4.3 面板复用与JSON导入导出

面板做完后,把它导出成JSON。导出的文件会包含templating部分,就是变量定义;还有panels部分,就是面板配置。换环境导入时,通常只需要做两件事:

一是数据源UID可能不同。如果新环境用的数据源和旧环境不是同一个,需要在导入时选择新的数据源,或者手动改JSON里的datasource.uid字段。

二是变量默认值。导入新环境后,建议先测试一遍变量下拉框能不能正常加载。有时候标签名在新环境还没生成,下拉框是空的,面板只能干瞪眼——这种情况不是导入失败,而是数据源里还没有指标。

关于复用,还有一个更轻量的方式:Grafana支持在Dashboard内部做Repeat面板,也就是按变量值重复渲染多个同样配置的面板。比如选了3个实例,3个CPU面板会并排出现。这个功能适合做“一个实例一个面板”的对比场景;但面板数量多时资源消耗会涨,用的时候要想清楚。

5. 常见问题与排查技巧实录

5.1 变量下拉框查不到值或一直转圈

这种情况十有八九是数据源里没有对应标签,或者标签名拼错了。我的排查顺序是:

  1. 先到Explore里执行label_values(标签名),确认标签是否存在。
  2. 如果标签存在但加了联动后查不到,检查上游变量值是否为空,比如dc没选上。
  3. 检查正则是否把结果全过滤掉了。正则字段是贪婪还是非贪婪,写错一个锚点就容易全空。
  4. 数据源权限问题:某些数据源账号被限制了查询范围,变量的label_values也可能被拒。

另外,如果变量值列表特别长,可以打开变量的“Allow custom all value”选项并设置一个自定义的全选值,比如用.*代替默认的All,这样查询时可以拼出instance=~".*",性能比=~"inst-a|inst-b|..."好很多。

5.2 数字对不上或者出现负数、百分比溢出

出现这种情况,先怀疑查询口径而不是面板。例如CPU使用率,如果直接在原指标上乘以100,容易忽略多个核心的聚合,导致某些机器显示大于100,这时考虑用avg without (cpu)或者只在node层面聚合。单位也很关键:如果原始指标是byte,面板单位却选了percent,数字自然不对。我习惯是所有查询先在Explore里跑一遍,确认数值和预期一致了,再粘到面板里,不要直接在面板里改来改去。

5.3 面板加载慢、下拉切换卡顿

面板加载慢的常见原因:一是每个面板的查询权重太高,比如对高基数标签做全量聚合,数据量巨大;二是时间范围拉得太长,$__interval过大过小都不好。优化的办法包括:给核心指标创建Recording Rule,把5分钟粒度、实例维度的值预计算;面板刷新时间不要设成1s,默认15s或30s就够;模板变量尽量用Query结果缓存,Grafana对变量查询其实有缓存机制,但多数据源场景下要注意。

如果面板数量实在太多,考虑拆成多个Dashboard,用Dashboard链接或跳转,而不是把几十个面板硬塞在一屏里。一屏超过20个面板,不仅加载慢,人眼也处理不过来。

5.4 排查速查表

现象可能原因快速排查方法
变量下拉框空标签不存在 / 正则过滤过度Explore执行label_values验证
多选变量查不出数据PromQL用了=而非=~检查匹配操作符
面板数字异常大单位配错 / counter未用rateExplore单查指标确认语义
面板加载缓慢高基数查询 / 时间范围过大开Recording Rule / 降低刷新频率
切换环境导入后空白数据源UID不同重新选择数据源或改uid
百分比超100聚合维度没收敛检查聚合方式与by子句

个人体会:做了这么多年监控面板,最大的心得不是学会了多少个面板组件,而是“标签和变量先行”这个习惯。无论指标怎么设计、面板怎么布局,变量一旦定下来,整个监控体系的面貌就定了。我后来接手别人的面板时,第一件事永远是看变量列表,而不是看图的样式,因为变量列表暴露了这整套监控的维度和边界。如果你刚开始做自定义面板,建议先花半小时把业务标签梳理清楚,再打开Grafana动手——这个顺序真的能省掉后面大半的返工。另外一个经验就是,面板写完了不要急着交付,把时间范围拉大到90天,再缩到5分钟,看看图像和数值会不会出现明显问题,这一步能提前发现大量查询口径的bug。希望这篇整理对你有用,也欢迎交流你遇到的变量和面板问题。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进