写一块看板,再做一个检查它的工具
目标
先写下四个问题,再用 JSON 亲自编写一个回答这些问题的状态仪表板。 然后创建检查该仪表板的工具,让机器代替你确认:每个面板是否写明要回答的问题、面板是否不超过六个、是否以比率查看 5xx,以及是否以百分位数查看延迟。
为什么重要
仪表板只会朝一个方向增长。任何人都能以“这个也能看到就好了”为理由添加面板,但要删除面板,就必须证明“没有人看这个”,而这几乎无从证明。如果为每个面板写明它回答的问题,就有理由删除没有对应问题的面板;再把检查器接入 CI,这条规则便不再依赖人工维持。
仪表板 JSON 的 diff 很难由人阅读。大量坐标和字段发生变化,评审很容易直接放行。创建一个由机器代为提问的位置,才是本实验的真正目的。
本实验不会启动 Grafana
这里处理的是仪表板 JSON 本身。启动 Grafana 并通过界面创建仪表板,将在本课程后面的实验中进行。这里仅编写文件和检查器。
步骤
- 在
/root/gfq/01-questions.md中写下此仪表板要回答的四个问题。每个问题是一句以问号结尾的话,并在问题下方以metric:开头的行中写明用什么指标回答。必须覆盖四个黄金信号(延迟、流量、错误、饱和度)。 - 在
/root/gfq/dashboard.json中编写状态仪表板。它必须具有uid,标题以问号结尾,并包含 4~6 个面板。每个面板的description都要以问号结尾,写明该面板回答的问题。必须各有一个标题包含5xx的面板和标题包含지연(或latency)的面板。 - 创建
/root/gfq/lint.py。python3 lint.py <JSON 경로>对每项违规输出一行VIOLATION <규칙id> <패널 제목>,最后输出violations=<개수>。第一条规则是no-description。将针对自己的仪表板运行所得结果保存到/root/gfq/03-lint-basic.txt。 - 添加规则集:
too-many-panels(面板超过 6 个)、error-count-not-ratio(标题包含5xx,但查询中没有除法)、latency-not-quantile(标题包含지연或latency,但查询中没有histogram_quantile)。使用故意违反各规则的文件进行测试,并将结果保存到/root/gfq/04-lint-full.txt。 - 在
/root/gfq/bad-dashboard.json中故意创建一个违反全部四条规则的仪表板,并将检查结果保存到/root/gfq/05-bad.txt。 - 将诊断面板拆分到
/root/gfq/diagnosis.json(至少三个面板,使用不同的uid),并让状态仪表板的links指向该uid。将检查面板数量和链接的结果保存到/root/gfq/06-split.txt。 - 再添加一条规则:
description-not-question——如果存在说明但不以问号结尾,则属于违规。使用说明为陈述句的文件进行测试,并将结果保存到/root/gfq/07-lint-e.txt。 - 在
/root/gfq/08-review.md中撰写评审。必须包含## 30초 시험、## 지운 패널、## CI 에 거는 이유三个小节,并体现状态、诊断和容量三类仪表板的区别。
参考
- 仅使用标准库的
json。该 Pod 无法访问外网,因此不能执行pip install。 - 面板查询位于
panel["targets"][i]["expr"]。一个面板可能有多个 target,将它们拼接后检查更安全。 - 通过 Grafana API 上传时会套上
{"dashboard": {…}}外层,因此检查器若使用doc.get("dashboard", doc)同时支持两种形式,之后即可直接复用。 - 5xx 比率的形式是
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))。请求数会随流量增加而增加,但用户实际遭遇失败的概率应以比率衡量。 - p95 为
histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))。le是桶边界,因此仅保留它进行聚合。 - 评分器会用你的检查器检查故意违规的文件。无条件输出
violations=0的检查器比没有检查器更糟,并会在此处失败。
先写问题
按照问题 → 面板的顺序进行。反过来就会变成“既然有这个指标,就画出来看看”,这样添加的面板以后无人能够解释。
四个黄金信号正好对应四个问题。
- 错误:当前是否正在向用户返回失败
- 延迟:是否变慢
- 流量:当前有多少流量进入
- 饱和度:资源是否即将耗尽
问题行应以问号结尾,并在紧接其下、以 metric: 开头的行中写明用什么指标回答。指标行必须体现错误应使用比率而不是数量。
用 JSON 编写状态仪表板
状态仪表板应包含 4~6 个面板。超过六个通常意味着混入了诊断面板,这样就无法在 30 秒内得到答案。
在每个面板的 description 中写明该面板回答的问题。如果无法用一句话写出来,说明连面板本身都不知道自己在观察什么,应将其列为删除候选。
标题也应采用问题形式。标题是问题时,没有回答该问题的面板会非常显眼。
评分器会检查:标题含 5xx 的面板,其查询中是否有除法;标题含 지연 或 latency 的面板是否使用 histogram_quantile。
创建检查器并加入一条规则
输出格式是一项契约。每项违规输出一行 VIOLATION <규칙id> <패널 제목>,最后输出一行 violations=<개수>。评分器会按原样查找这两种格式。
第一条规则 no-description:面板没有 description 或内容为空时即为违规。
使用 json.load() 读取,并通过 doc.get("dashboard", doc) 支持 Grafana API 外层,之后即可直接复用。
对自己的仪表板运行时不应出现违规。如果出现,请返回第 2 步补全说明。
添加规则集并测试能否捕获违规
只确认检查器能让文件通过,仅完成了一半。还必须放入故意违规的文件,确认它能够捕获。无条件通过的检查器比没有更糟——它会在系统没有真正学会时声称已经学会,而且无人报告问题。
规则集如下。
too-many-panels——面板超过 6 个。按仪表板计数一次。error-count-not-ratio——标题包含5xx,但查询中没有/。latency-not-quantile——标题包含지연或latency,但查询中没有histogram_quantile。
请在 /root/gfq/fixtures/ 等位置创建测试文件并运行检查器。必须把输出保存到结果文件,才能留下规则名称。
创建违反全部四条规则的仪表板
常见的“图表墙”正是这种样子:与用户体验无关的进程内部指标一字排开;5xx 以数量绘制;延迟使用平均值;说明为空。
请将以下四项全部放进同一个文件。
- 至少七个面板
- 标题包含
5xx、但查询中没有除法的面板 - 标题包含
지연、但没有histogram_quantile的面板 description为空的面板
这个故意创建的文件将成为检查器的回归测试。每次修改规则后都可对它运行检查。
将诊断面板拆分到另一仪表板
一旦把诊断面板混入状态仪表板,该页面就无法在 30 秒内给出答案。不是删除,而是迁移——迁移后通过链接连接,需要时即可一步跳转。
诊断仪表板用于放置查找原因的面板,例如 CPU、GC、连接池等待、各处理器错误率。它的 uid 必须与状态仪表板不同。
状态仪表板的 links 采用如下形式。
"links": [{"type": "dashboards", "title": "왜 아픈가 — 진단", "url": "/d/<진단 uid>"}]
请在结果文件中保存确认两个仪表板面板数量和链接的输出。
进一步检查说明是否为问题
如果说明是陈述句,只会留下“画了什么”,却丢失“为什么要看”。“显示 5xx 请求的比率”只是看面板就能知道的内容,没有增加任何信息。
强制要求问号,可以暴露写不出问题的面板,而这些面板就是删除候选。
规则名为 description-not-question。完全没有说明时属于 no-description,因此请将两条规则分开,避免重叠计数两次。
自己的仪表板仍应保持零违规。
撰写事故评审
仪表板完成后进行事故测试。假设凌晨 3 点被叫醒,打开该仪表板后能否在 30 秒内判断系统是否正常?如果不能,通常不是面板太少,而是太多。
请编写三个小节。
## 30초 시험——按什么顺序查看,用什么作出判断## 지운 패널——删除了什么以及原因;在这里体现状态、诊断、容量三类仪表板的区别## CI 에 거는 이유——检查器能阻止什么
还可以写明:当标题是问题时,没有回答该问题的面板会变得显眼。