50.6 看板设计
一句话
看板不是图表的集合,而是一次决策的视觉化——先定「谁、在什么场景下看、看完要做什么决定」,再决定放哪六个图;判断看板好坏的标准不是「信息全」,而是看完的人能不能在 30 秒内做出正确的下一步动作。
先定场景,再定图
| 场景 | 谁看 | 停留时间 | 必须回答 | 图上限 |
|---|---|---|---|---|
| 值班首屏 | on-call | 30 秒 | 是不是我们的问题?影响多大?从几点开始? | 6 |
| 服务详情 | 该服务 owner | 2 分钟 | 哪一跳慢/错?哪个实例?和发布有关吗? | 8–12 |
| 资源详情(USE) | SRE | 1 分钟 | 哪个资源饱和?多久会耗尽? | 6 |
| 依赖详情 | 上下游团队 | 1 分钟 | 是依赖的问题还是我们的问题? | 6 |
| 业务看板 | 产品 / 业务 | 1 分钟 | 用户还能不能下单/支付?掉了多少? | 4–6 |
| 复盘看板 | 全员 | 5 分钟 | 长期趋势、容量、SLO 达成情况 | 10–15 |
第一件要放弃的幻想:一张大屏给所有人看。给老板看的(业务)、给 on-call 看的(症状)、给 owner 看的(内部步骤)是三种不同的问题,塞在一屏里必然谁都不满意。
首屏六格:把决策顺序画成布局
┌──────────────────┬──────────────────┬──────────────────┐
│ ① SLO / 预算剩余 │ ② 错误率 vs 阈值 │ ③ 最近变更 │
│ 99.93% 剩 62% │ 0.07% ▁▂▁█▁ │ 14:02 deploy v3.2│
├──────────────────┼──────────────────┼──────────────────┤
│ ④ 请求速率 RPS │ ⑤ 延迟 P50/95/99 │ ⑥ 饱和度 │
│ 1.2k/s ↑12% │ 8 / 45 / 210ms │ DB 连接池 82% │
└──────────────────┴──────────────────┴──────────────────┘
布局不是审美,是决策顺序:
- 左上 = 结论:SLO 与预算剩余,一眼看出「今天还能不能烧」。
- 中上 = 与目标的差:错误率曲线 + 阈值线,判断「要不要动手」。
- 右上 = 最近的变量:发布、配置变更、扩缩容。排障的第一猜想永远是「刚才改了什么」——业界经验是多数线上故障由变更引入(不同组织差异很大,但把它放在首屏几乎零成本)。
- 下一行 = 四黄金指标:速率、延迟、饱和度,配合错误率构成完整的 RED + 饱和。
🔑 首屏的门槛:一个刚接手的人,只看这一屏,能判断「要不要升级、要不要回滚、要不要扩」。做不到就说明缺的不是图,是结论。
每个面板的规范
| 要素 | 要求 | 反例 |
|---|---|---|
| 标题 | 写结论或问句,不写指标名 | rate(http_requests_total[5m]) |
| 单位 | 显式:ms、req/s、%、GB | 裸数字,读者自己猜 |
| 时间范围 | 与决策匹配:首屏 1 h/6 h,复盘 30 d | 全部用 30 d(尖刺被压平) |
| 对比 | 上周同期、上一个发布点 | 只看当前值,判断不了「这是不是异常」 |
| 阈值线 | 把 SLO 线、容量线画在图上 | 让读者脑补红线在哪 |
| 颜色 | 只有越界才用红;正常不用绿 | 一片绿 = 没有绿;全彩 = 没有重点 |
| 图例 | ≤ 5 条序列,命名带维度值 | 20 条线叠在一起,谁也看不清 |
| 下钻 | 每个面板都能点进 trace / 日志 / 实例 | 只能看,不能跳 |
图类型跟着问题走
| 问题 | 图 | 例子 |
|---|---|---|
| 随时间怎么变 | 折线(≤ 5 条) | RPS、P99、错误率 |
| 分布怎么迁移 | 热图(histogram heatmap) | 延迟分布随时间整体右移 |
| 现在是否越界 | 单值 + 阈值条 | 错误预算剩余 62% |
| 由什么构成 | 堆叠面积(≤ 5 类) | 5xx 按错误码构成 |
| 谁最差 | 表格 / 条形 TOP-N | 最慢的 10 个路由 |
| 两个量是否相关 | 散点 | 延迟 vs 连接池占用 |
反例:用饼图看趋势、用双 Y 轴强行对齐两个量纲、3D 效果、超过 5 条线的折线。这些不是「不好看」,是「会读出错误结论」。
关联与下钻:看板的价值在跳转
| 你看到 | 下一步点哪 | 带什么参数 |
|---|---|---|
| 错误率尖刺 | exemplar → 一条慢/错 trace | trace_id |
| trace 里某个 DB span 慢 | 该 span 时间窗内的日志 | trace_id + 时间范围 |
| 某个实例指标异常 | 主机/容器看板 | host.name / pod |
| 依赖错误率上升 | 依赖方的服务看板 | service.name |
| 延迟整体上移 | 「最近变更」面板 | 发布时间窗 |
🔑 一个看板如果只能「看」不能「跳」,它就是一张截图。排障真正的时间花在三个系统之间搬参数——把
trace_id、service.name、host.name做成可点的链接,比多加十个图有用。
全栈监控三层:每层看什么
| 层 | 内容 | 主要数据 | 关键面板 |
|---|---|---|---|
| 基础层 | CPU、内存、磁盘容量与 IO、网络吞吐与丢包 | 指标(USE) | 饱和度、剩余可用时间 |
| 中间层 | MySQL(连接、慢查询、复制延迟)、Redis(命中率、内存、evict)、Kafka(积压、ISR)、连接池 | 指标 + 日志 | 积压趋势、慢查询 TOP |
| 应用层 | 入口吞吐/延迟/状态码、调用链、性能瓶颈、前端体验 | 指标 + 链路 + 日志 | RED、trace 列表、错误聚类 |
四个验收问题
看板做完了,用这四个问题验收。答不上来,说明缺的不是面板,是关联维度:
| 问题 | 需要什么才能答 |
|---|---|
| 一台机器挂了,会影响哪些对外 API? | service.name ↔ host.name ↔ 路由 的关联表/拓扑 |
| 一个 API 变慢,是 GC、资源不足,还是依赖慢? | 同一时间窗内的 GC/饱和度指标 + trace 的 span 拆分 |
| 一条 SQL 变慢,会影响哪个对外 API? | 从 DB 实例反查到调用方服务,再到入口路由 |
| MQ 积压了,会影响哪些 API? | 消费组 → 服务 → 路由的依赖图 |
TOP-N 三视图
排障时最有用的三个排名,缺一不可:
| 视图 | 排序依据 | 回答 |
|---|---|---|
| 按调用量 | 请求数降序 | 哪些接口承载主要流量(先保它们) |
| 按最耗时 | P99 或总耗时降序 | 哪里最慢(优化收益最大) |
| 按热点 | 单实例/单 key 的集中度 | 是否有个别实例或热点 key 在拖后腿 |
图和告警同源:recording rules
groups:
- name: route-recording
interval: 30s
rules:
- record: route:http_requests:rate5m
expr: sum by (route) (rate(http_requests_total[5m]))
- record: route:http_errors:ratio5m
expr: |
sum by (route) (rate(http_requests_total{code=~"5.."}[5m]))
/
sum by (route) (rate(http_requests_total[5m]))
面板与告警都查 route:http_errors:ratio5m,就不会出现“图上 5m、告警 1h”的口径漂移;改口径只改一处。recording rules 用 promtool check rules 校验;告警规则的单测见 50.5 告警。
告警响了之后谁接、怎么升级,见 56.3 on-call (值班 / 升级路径 / runbook)。
promtool check rules /etc/prometheus/rules/*.yml
# 面板/告警引用了不存在的 recording rule → 直接搜出来
grep -R "route:http_errors:ratio5m" dashboards/ rules/
一条纪律:看板上的每个数字,要么来自 recording rule,要么来自一条能在告警里复用的查询;否则同一个指标迟早出现两种口径。
看板的生命周期
- 看板即代码:JSON 进 Git,改动走 PR。手改 UI 的看板三个月后没人知道某个图为什么在那。
- 每块面板有 owner:写在标题或描述里;没有 owner 的面板默认「可删」。
- 季度清理:30 天无人访问的看板归档(Grafana 有 usage stats)。看板数量本身就是一种技术债。
- 告警与看板同源:告警里的 PromQL 就是看板里的查询;否则会出现「图上正常、告警在响」这种最伤信任的情况。
- 新服务上线即带看板:模板化(同样的 RED + USE 布局),而不是等出事再手工搭。
反模式
| 反模式 | 后果 |
|---|---|
| 把所有指标都堆上去(200 个图) | 首屏失去焦点,排障变成「找图」 |
| 用平均值做主图 | 长尾不可见,用户投诉与看板长期矛盾 |
| 没有变更标注 | 排障时要挨个问「刚才谁发布了」 |
| 各面板时间范围不一致 | 无法目视关联,A 图 1 h、B 图 30 d |
| 每个服务手工一套看板 | 新服务上线没有看板,故障时靠猜 |
| 看板无 owner、无清理 | 半年后没人敢删,也没人看得懂 |
| 红绿滥用、彩虹配色 | 一片红等于没有红 |
| 看板与告警用两份查询 | 「图上正常、告警在响」,团队开始不信监控 |
| 把看板当告警(人盯屏) | 没人盯的时段就是盲区(50.5 告警) |
自检
Q1 为什么首屏必须有「最近变更」面板?
▸ 答案:排障的第一个假设应该是「刚才改了什么」,因为变更(发布、配置、扩缩容、开关)是最常见的故障触发器,而且它给出的动作(回滚)往往最快见效。把发布时间点画在指标图上,能让「指标从 14:02 开始变坏」与「14:02 有一次发布」在视觉上直接对齐,省掉最耗时的一轮「挨个问人」。
Q2 一个看板放 200 个图,问题出在哪?
▸ 答案:看板服务的是一次决策,200 个图意味着没有决策目标,读者要在里面「找」而不是「看」。具体代价:① 首屏失去焦点,异常信号被淹没;② 加载慢、查询贵;③ 没人维护,图例与指标名半年后过期;④ 无法判断哪块该删。正确做法是按场景拆成多个看板(首屏 6 图、服务详情 8–12 图),用下钻连接。
Q3 「一台机器挂了,会影响哪些对外 API」——这个问题需要什么数据才能回答?
▸ 答案:需要三层关联:主机/容器 → 运行在其上的服务实例(host.name/pod ↔ service.name)→ 服务对外暴露的路由(service.name ↔ route)。只有指标没有关联维度时,这个问题无法回答——你能看到「这台机器 CPU 掉了」,但说不出影响面。所以看板的前提是统一的资源命名(见 50.1 三支柱与成本模型),而不是更多的图。
Q4 为什么看板与告警必须用同一条查询?
▸ 答案:否则会出现「图上一切正常,告警在响」或者反过来。原因通常是两份查询的过滤条件、窗口、聚合方式不同(图上是 sum by (route),告警是 sum 全局;图上用 5 m,告警用 1 h)。这种不一致会直接摧毁团队对监控的信任,进而导致「告警响了先关掉」——比没有告警更糟。
Q5 延迟分布为什么用热图而不是 P99 折线?
▸ 答案:P99 折线只给一条分位线,会掩盖「分布形状的变化」:双峰(缓存命中/未命中)、整体右移、或者长尾变厚,在单条线上看起来可能一样。热图(时间 × 延迟桶 × 计数)能直接看到分布怎么迁移,判断是「整体变慢」还是「一小撮请求变慢」。代价是读图门槛更高,所以热图放在服务详情页,首屏仍用 P50/P95/P99 三条线。