Grafana Dashboard 设计实战——让 Dashboard 真正能帮你发现问题
Grafana Dashboard 设计实战——让 Dashboard 真正能帮你发现问题
适读人群:使用 Grafana 做监控的工程师 | 阅读时长:约18分钟 | 核心价值:从 Dashboard 设计原则到实际配置,让你的 Dashboard 从"看起来很酷"变成"真正有用"
我见过太多"装饰性 Dashboard"了。
那种 Dashboard 有几十个图表,各种颜色,密密麻麻,看起来非常专业。但出了故障,没有人知道该看哪个图表,所有图表都有数据,但没有一个图表能直接告诉你"这里出了问题"。
有一次我们的支付服务出了问题,值班工程师打开 Dashboard,对着几十个图表看了 5 分钟,没有找到问题在哪。最后还是靠日志搜索找到的。
Dashboard 的失败不在于图表太少,在于设计的目的不清晰。这篇文章讲的就是如何设计真正有用的 Grafana Dashboard。
Dashboard 设计的三个层次
好的监控 Dashboard 应该回答三个层次的问题:
第一层:现在有没有问题?(5 秒内能看出来)
- 服务是否健康
- 关键 SLI 是否在正常范围内
第二层:如果有问题,问题在哪?(1 分钟内能缩小范围)
- 是哪个服务、哪个接口、哪个实例出了问题
- 是流量问题、错误问题,还是延迟问题
第三层:问题的根因是什么?(通过深入图表分析)
- DB 慢查询、内存压力、外部依赖异常
大多数团队的 Dashboard 只有第三层——满屏的指标图表,适合深入分析,但第一层(快速判断是否有问题)几乎没有做。
服务 SLO Dashboard 设计
关键 SLI 状态面板(第一层)
在 Dashboard 的最顶部放一排 Stat Panel,一眼就能看出关键指标的健康状态:
Grafana JSON 配置(可导入):
{
"panels": [
{
"type": "stat",
"title": "Availability (1h)",
"gridPos": {"x": 0, "y": 0, "w": 4, "h": 4},
"options": {
"colorMode": "background",
"thresholds": {
"steps": [
{"color": "red", "value": 0},
{"color": "yellow", "value": 99},
{"color": "green", "value": 99.9}
]
}
},
"targets": [
{
"expr": "(1 - sum(rate(http_requests_total{status=~'5..'}[1h])) / sum(rate(http_requests_total[1h]))) * 100",
"legendFormat": "Availability"
}
]
},
{
"type": "stat",
"title": "P99 Latency (5m)",
"gridPos": {"x": 4, "y": 0, "w": 4, "h": 4},
"options": {
"colorMode": "background",
"unit": "ms",
"thresholds": {
"steps": [
{"color": "green", "value": 0},
{"color": "yellow", "value": 500},
{"color": "red", "value": 1000}
]
}
},
"targets": [
{
"expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)) * 1000",
"legendFormat": "P99"
}
]
},
{
"type": "stat",
"title": "Error Rate (5m)",
"gridPos": {"x": 8, "y": 0, "w": 4, "h": 4},
"options": {
"colorMode": "background",
"unit": "percentunit",
"thresholds": {
"steps": [
{"color": "green", "value": 0},
{"color": "yellow", "value": 0.001},
{"color": "red", "value": 0.01}
]
}
},
"targets": [
{
"expr": "sum(rate(http_requests_total{status=~'5..'}[5m])) / sum(rate(http_requests_total[5m]))",
"legendFormat": "Error Rate"
}
]
}
]
}这三个 Stat Panel 用颜色编码(绿/黄/红)直接告诉值班工程师:"现在有没有问题"。
时序图表(第二层)
在 Stat Panel 下面放时序图表,用于分析趋势:
请求速率分解:按状态码分层,能直观看出 5xx 的比例
PromQL:
# 成功请求
sum(rate(http_requests_total{status!~"5.."}[1m]))
# 服务器错误
sum(rate(http_requests_total{status=~"5.."}[1m]))
# 客户端错误(通常不算服务故障)
sum(rate(http_requests_total{status=~"4.."}[1m]))在 Grafana 里,把这三个 query 叠加到同一个图表,用不同颜色(绿色=成功,红色=5xx,橙色=4xx),能一眼看出异常发生的时间点。
延迟分位数图表:同时展示 P50、P95、P99
P50: histogram_quantile(0.5, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
P95: histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
P99: histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))只看平均延迟是危险的——平均值会掩盖尾部用户的痛苦。P99 才能反映最慢的那 1% 用户的体验。
接口级别的 Dashboard(第二层细化)
服务级别 Dashboard 显示服务整体状态,接口级别 Dashboard 帮你找到是哪个接口出了问题。
用 Variable 实现动态过滤:
在 Dashboard 设置里添加 Variable:
Variable Name: endpoint
Type: Query
Data source: Prometheus
Query: label_values(http_requests_total, uri)
Multi-value: true
Include All option: true然后在图表的 PromQL 里用这个变量:
sum(rate(http_requests_total{uri=~"$endpoint"}[5m])) by (uri, status)这样 Dashboard 顶部会出现一个下拉框,选择某个接口就只看那个接口的数据,选 All 看所有接口的对比。
Top N 慢接口图表:
# P99 最慢的 10 个接口
topk(10,
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (uri, le)
)
)这个图表能立刻告诉你哪些接口是性能瓶颈。
JVM Dashboard 设计
Java 服务的 JVM 状态很重要,但图表太多容易迷失。我的建议是只放最关键的几个:
# 关键 JVM 面板(按优先级)
# 1. 堆内存使用趋势(带使用率颜色编码)
jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"}
# 2. GC 停顿时间(每分钟 GC 总停顿时间,超过一定值说明 GC 压力大)
increase(jvm_gc_pause_seconds_sum[1m])
# 3. GC 次数(Old Gen GC 次数多说明内存紧张)
rate(jvm_gc_pause_seconds_count{cause!~".*Minor.*"}[5m])
# 4. 线程数趋势(线程泄漏会导致线程数一直增长)
jvm_threads_live_threads
# 5. 非堆内存(Metaspace)
jvm_memory_used_bytes{area="nonheap"}踩坑实录
踩坑一:Dashboard 图表太多,加载慢到没人用
我们有个 Dashboard,一打开就要加载 35 个 PromQL 查询,打开一次要 10 秒以上,大家都不愿意用它。
Dashboard 性能优化建议:
- 默认时间范围设短:默认展示最近 30 分钟,而不是 24 小时,数据量小加载快
- 图表数量控制在 20 个以内:超过 20 个通常意味着需要拆分
- 用
step参数降低数据点密度:在 Query Options 里设置 Min step,不要让 Prometheus 返回太多数据点 - 避免高基数的 label 在 by 子句里:
by (pod_name)如果有 100 个 pod,会返回 100 条时序,渲染慢
踩坑二:颜色阈值设置不合理,永远是绿色
我们有个图表,P99 延迟的告警阈值设的是 30 秒(红色),黄色是 10 秒。结果这个服务的 P99 实际上大部分时间在 2-3 秒,图表永远是绿色。
但实际上 2-3 秒的 P99 对一个用户界面的 API 来说已经很慢了,只是阈值设太宽松了,图表看起来健康。
阈值的设置要基于 SLO,而不是随手填一个数字:
- 如果你的 SLO 是 P99 < 500ms,那 400ms 就应该是黄色,500ms 是红色
- 如果你不知道合理的阈值是多少,先收集 1 个月的历史数据,根据实际基准设置
踩坑三:Dashboard 只有图表,没有文字说明
在复盘会上展示 Dashboard 时,团队里的新人完全不知道某个图表是什么意思,哪里是正常、哪里是异常。
好的实践:每个图表都加 Panel Description(右上角的 ⓘ 图标),说明:
- 这个图表监控的是什么
- 正常范围是多少
- 如果异常应该怎么处理(或指向 runbook)
在重要的图表旁边也可以加 Text Panel,当指南针用。
Dashboard 组织方式
按服务分 Dashboard:每个服务一个 Dashboard,Dashboard 链接到通用的"基础设施 Dashboard"(host/K8s 集群层面的指标)
Dashboard 层级:
全局概览 Dashboard
└── 服务 A Dashboard
└── 接口级别 Dashboard(用 Variable 切换)
└── 实例级别 DashboardDashboard 命名规范:
[团队] 服务名 - Dashboard类型
例如:[Payments] payment-service - Overview
[Platform] K8s Cluster - Resource Usage实战:一个完整的服务 Overview Dashboard 配置
以下是我在生产中使用的 Dashboard 布局,从上到下按"概览→趋势→明细"的顺序排列:
Row 1:状态面板(5秒判断健康度)
- Stat: Availability (1h) ← 绿黄红三色
- Stat: P99 Latency (5m) ← 绿黄红三色
- Stat: Error Rate (5m) ← 绿黄红三色
- Stat: Throughput (1m) ← 显示当前 QPS
- Stat: Instances Up ← 在线实例数
Row 2:时序图(趋势分析)
- Time series: Request Rate(按状态码分色叠加)
- Time series: P50/P95/P99 延迟
- Time series: Error Rate 趋势
Row 3:JVM 状态
- Time series: JVM Heap 使用率
- Time series: GC 次数和停顿时间
- Time series: 线程数趋势
- Gauge: 当前 Heap 使用率(带颜色阈值)
Row 4:依赖服务状态
- Time series: 数据库连接池使用率
- Time series: Redis 命中率
- Time series: 外部 API 调用延迟和错误率
Row 5:Top N 慢接口(按需展开)
- Table: P99 最慢的 10 个接口
- Table: 错误率最高的 10 个接口
这个布局让值班工程师的视线从上往下扫一遍,第一行告诉你"有没有问题",第二行告诉你"问题从什么时候开始",第三行告诉你"JVM 层面有没有异常",第四行告诉你"依赖服务有没有问题",第五行告诉你"具体哪个接口出了问题"。
让 Dashboard 和 Alerting 联动
Dashboard 和告警是互补的:
- 告警:主动推送,告诉你"有问题"
- Dashboard:被动查看,帮你"找到问题"
两者结合的最佳实践:
告警里加 Dashboard 链接:
# Prometheus 告警规则
- alert: HighErrorRate
annotations:
dashboard_url: "https://grafana.company.com/d/service-overview?var-service={{ $labels.service }}&from=now-30m"收到告警后,点击链接直接跳转到对应服务在告警时间点的 Dashboard,不需要手动去 Grafana 搜索。
Dashboard 里加告警状态面板:
在 Dashboard 顶部加一个 Alert List Panel,显示当前激活的告警列表。值班工程师打开 Dashboard 就能看到所有当前问题,不需要去 Alertmanager 里查。
Dashboard as Code:用 Grafonnet 管理 Dashboard
手动在 Grafana UI 里拖拽创建 Dashboard 的问题:
- 无法版本控制(谁改了什么不知道)
- 无法复用(多个服务需要同样结构的 Dashboard,每个都要手动创建)
- Grafana 升级可能导致 Dashboard JSON 格式变化
推荐用 Grafonnet(Grafana 的 Jsonnet 库)来用代码生成 Dashboard:
// service-dashboard.jsonnet
local grafana = import 'grafonnet/grafana.libsonnet';
local dashboard = grafana.dashboard;
local statPanel = grafana.statPanel;
local timeSeries = grafana.timeSeries;
dashboard.new(
title='Service Overview',
tags=['service', 'overview'],
refresh='30s',
)
.addTemplate(
grafana.template.datasource('datasource', 'prometheus', 'Prometheus')
)
.addPanel(
statPanel.new(
title='Availability (1h)',
datasource='$datasource',
)
.addTarget(
grafana.prometheus.target(
'(1 - sum(rate(http_requests_total{status=~"5.."}[1h])) / sum(rate(http_requests_total[1h]))) * 100',
legendFormat='Availability'
)
)
.setThresholds([
{value: 0, color: 'red'},
{value: 99, color: 'yellow'},
{value: 99.9, color: 'green'},
]),
gridPos={x: 0, y: 0, w: 4, h: 4}
)用代码管理 Dashboard,可以提交到 Git,做 Code Review,用 CI 自动部署到 Grafana。多个服务共享同一个 Dashboard 模板,修改模板就能更新所有服务的 Dashboard。
深度解析:Dashboard 的用户视角设计
很多工程师在设计 Dashboard 时,思路是"我有这些指标,怎么把它们都展示出来"。这是反向的——正确的思路应该是"用户需要回答什么问题,我的 Dashboard 如何帮他们找到答案"。
四类常见的 Dashboard 使用场景
第一类:值班巡检(每天早上看一眼)。目的是快速确认系统整体正常。这类 Dashboard 应该极度精简——只有最关键的健康指标,绿了就关掉,红了才深入看。通常一个屏幕能看完,不需要滚动。
第二类:故障排查(出了问题时用)。目的是找到问题根因。这类 Dashboard 需要更多细节:各服务的错误率趋势、P50/P99 延迟对比、关键依赖(数据库、缓存、外部接口)的健康状态。能快速缩小"问题在哪个服务、哪个组件"的范围。
第三类:容量规划(定期回顾)。目的是预判瓶颈。这类 Dashboard 关注长时间趋势(30 天、90 天),资源使用率的增长斜率,帮助判断什么时候需要扩容。通常不需要实时刷新。
第四类:业务 Dashboard(给产品/业务方看)。目的是让非工程师了解系统状态和业务健康度。这类 Dashboard 要"去技术化":用业务术语标注("今日下单量"而不是 "order_created_total counter"),颜色和布局要直观,不需要懂 Prometheus 也能看懂。
给 Dashboard 写使用说明
每个 Dashboard 都应该有一段文字说明,放在 Dashboard 顶部:这个 Dashboard 是给谁用的?什么时候应该看这个 Dashboard?每个 Panel 的核心含义是什么?遇到什么情况应该 escalate?
这听起来像废话,但在凌晨三点叫起来的值班工程师面前,一段清晰的说明可以节省 10 分钟的摸索时间。Dashboard 不只是数据展示工具,也是团队知识的载体。
深度解析:Grafana 生态的扩展能力
很多人只用 Grafana 展示 Prometheus 数据,但 Grafana 的能力远不止于此。理解这些扩展能力,有助于用更少的工具覆盖更多的需求。
多数据源支持
Grafana 支持几十种数据源:Prometheus、Loki(日志)、Tempo(追踪)、Elasticsearch、PostgreSQL、MySQL、InfluxDB……这意味着你可以在一个 Grafana 实例里,同时展示指标、日志、追踪数据,甚至直接查询数据库的业务数据。
对于很多中小团队,Grafana + Prometheus + Loki + Tempo 的组合,可以完整覆盖"指标 + 日志 + 追踪"三大支柱,而且都是 Grafana 家族的产品,集成体验好,运维成本低。这是一个值得认真评估的技术栈。
Grafana Alerting
Grafana 8.0+ 引入了统一的告警系统(Unified Alerting),可以基于任何数据源创建告警规则,而不只是 Prometheus。这意味着你可以直接在 Grafana 里管理所有告警,包括基于日志的告警("Loki 里的 ERROR 日志超过 50 条/分钟")和基于 Prometheus 指标的告警,统一路由到 Alertmanager 或者直接发送到钉钉/Slack/PagerDuty。
对于中小团队来说,这简化了告警体系的架构——不需要单独管理 Prometheus 的 alerting rules 和 Loki 的 alert rules,全部在 Grafana 里统一配置,减少了需要维护的系统数量。
Grafana 的权限管理
Grafana 支持精细的权限管理:不同的用户组可以有不同的 Dashboard 访问权限。业务方只能看业务 Dashboard,不能修改;工程师可以看和修改技术 Dashboard;只读账号给给领导汇报用。
在数据安全要求高的场景(比如不同 BU 的数据不能互看),可以用 Grafana 的 Organization 功能做数据隔离——不同 Organization 有完全隔离的数据源、Dashboard 和用户,一个实例支撑多个团队使用。这对于平台团队同时服务多个业务方的场景非常实用。
把这套思路落地,你的 Dashboard 就能从"看起来很酷"变成"真正能帮你解决问题"。
深度解析:Dashboard 的生命周期管理
Dashboard 建好了,后续的维护同样重要。很多团队的 Grafana 里有几十上百个 Dashboard,一半以上是某个工程师某次测试时创建的,从来没人看,但没人敢删。这种"Dashboard 坟场"会让真正有价值的 Dashboard 淹没在噪音里。
定期清理无用 Dashboard
每季度做一次 Dashboard 审查:超过 3 个月没有人访问过的 Dashboard,发邮件给创建者询问是否还需要,两周内无回应就归档删除。Grafana 提供 API 可以查询 Dashboard 的访问时间,自动化这个清理流程不难。
Dashboard 所有权
每个 Dashboard 应该有明确的"Owner"——负责这个 Dashboard 的团队或个人。Owner 的职责是:当监控的服务发生变化时,及时更新 Dashboard;当有人反馈 Dashboard 看不懂时,提供解释和改进;当告警触发指向这个 Dashboard 时,确保 Dashboard 能帮助排查。
没有 Owner 的 Dashboard 往往会逐渐失效:服务改名了但 Dashboard 里还是老名字,告警规则更新了但 Dashboard 里的阈值线没跟上,最终 Dashboard 变得毫无意义却没有人知道应该修。
Dashboard 作为"活文档"
好的 Dashboard 不只是展示数据,也是系统架构的可视化文档。通过一个架构清晰的 Dashboard,可以快速了解"这个服务依赖哪些下游"、"它的核心业务指标是什么"、"它的 SLO 是多少"。这些信息如果只存在于 WIKI 文档里,很容易过时;而 Dashboard 因为直接连接到实时数据,反而能保持"活"的状态。
把 Dashboard 设计成"帮新人快速了解系统"的工具,是一个双赢的思路:既改善了 Dashboard 的可用性,也降低了新成员的上手成本。这种思维转变,让 Dashboard 的投入产出比大幅提升。
总结
Dashboard 是一个工具,工具要为目的服务。
好的 Dashboard 设计的核心是:为具体的使用场景设计,而不是展示你能收集到的所有指标。
值班工程师看 Dashboard 的目的是什么?判断是否有问题,找到问题在哪,理解问题的规模。围绕这三个目的设计 Dashboard,少即是多。
记住三个关键点:第一,状态面板放顶部,5 秒内能判断健康度;第二,时序图展示趋势,帮助判断问题的时间维度;第三,Dashboard 和告警联动,告警触发时一键跳转到相关 Dashboard。
