25.4 把观察契约变成告警
规则语法正确,只证明 parser 接受了它。
一条生产告警还必须同时通过:
本章生成的文件:
它们是教学候选,不是在线配置。
25.4.1 SLO 燃烧率与用户影响
从 error ratio 到 burn rate
若 SLO target 为:
允许的 bad ratio:
某窗口实际 bad ratio 为 $E$,燃烧率:
例如:
若持续 28 天,会花掉 14.4 倍预算;若只持续 1 小时,约花掉:
这解释了为什么 14.4x/1h 常被用作“快速消耗约 2% 月度预算”的起点。它是 政策起点,不是自然常数。
为什么使用两个窗口
只用长窗口:
只用短窗口:
组合:
长窗确认预算风险,短窗确认问题仍在发生。
本章可用性 fast burn
记录规则预先计算五个窗口:
fast:
标签固定:
fast、slow 与 ticket 是一套政策
| 规则 | 长/短窗 | burn | for |
路由 |
|---|---|---|---|---|
| fast | 1h / 5m | 14.4x | 2m | SEV-1 page |
| slow | 6h / 30m | 6x | 5m | SEV-2 page |
| budget | 3d / 6h | 1x | 15m | ticket |
它们不是三个独立“数据库报警”:
- fast 处理快速用户损害;
- slow 处理持续预算风险;
- ticket 处理应进入 backlog 的可靠性债务。
当 fast firing 时,同一 service/environment/objective 的 slow 和 ticket 可以 被抑制,避免一个事件三次通知;原始 alert state 和证据仍保留。
burn threshold 必须跟 target 绑定
延迟目标是 99%:
可用性目标是 99.9%:
把同一个绝对 error ratio 复制过去会错一个数量级。
规则生成器若使用 policy object,应从:
计算,而不是在 YAML 中散落魔法数。
event ratio,不是 instance ratio
错误写法:
它算的是实例比例,不是用户 event ratio。三节点中一个 down:
- 服务可能完全正常;
- 某些 read path 可能降级;
- failover 可能正在进行;
- 用户失败比例不一定是 1/3。
正确 availability SLI 来自 application outcome:
instrumentation 要预初始化 bounded outcome series,否则“没有 bad outcome series”与“零 bad events”会混淆。
latency 规则暴露了治理缺口
第 24 章定义 SLO-LATENCY,但 accepted alert list 没有 latency candidate。
本章没有悄悄将它变成生产 page,而是:
规则和测试都存在,生产门禁仍拒绝。这体现:
owner 还要决定:
- latency threshold 是否 250 ms;
- eligible event 与 availability 是否相同;
- success 但慢、failure 且慢如何计数;
- 低流量如何处理;
- page severity;
- 首个安全动作;
- 与 availability page 如何去重。
freshness 必须使用 commit-correlated event
规则:
分母是携带已知 commit token 的 probe,bad 是五秒内不可见。
不要替换成:
因为 pg_lag 的语义、空闲行为和用户 path 都不同。
正确性不燃烧
它没有:
一个未解释 mismatch 就进入完整性响应。缺失或 stale reconciliation 是另一个 control failure,不是零 mismatch。
恢复就绪也是 control
候选:
它应:
- block 高风险 release 或建立 ticket;
- 引导查看不可变 restore manifest;
- 安排隔离 restore drill;
- 不把 backup success 当替代。
当前第 24 章已定义 control objective,但告警候选仍待接受,所以走 test sink。
容量预测先要求 reviewed
为什么第二个条件重要?
都可能产生虚假线性 forecast。未经评审的模型不应 page。即使 reviewed,也默认 ticket,因为当前没有用户损害。
用户影响必须写进规则
同一个 threshold 若不能说明 user impact,就不能决定 severity:
这也是为什么 PG36HostCpuHigh 保持 diagnostic。
25.4.2 阈值、持续时间、去抖、抑制与分组
threshold 是政策,不是颜色
阈值来源可以是:
- SLO/error budget;
- control objective;
- 容量 horizon;
- 安全/完整性不变量;
- 组件规格;
- 统计/历史基线;
- 供应商硬限制。
每种来源对应不同动作。不要在 Grafana 中选一个“看起来红”的值,然后反向写 解释。
for 的状态机
典型:
for 不是简单 sleep:
- evaluation interval 决定检查粒度;
- rule error 与 no-data 的行为不同;
- restart/state persistence 要配置;
- data delay 可能让最新点不可见;
- label set 改变会创建新的 alert identity;
- 短暂 false 可重置 pending。
VMAlert 文档说明:no data 会重置 pending;evaluation error 则不会按普通 false 处理,而会保留此前状态。必须监控 rule error,不能只看业务 alert。
for 不能修复错误语义
仍然不知道用户是否受损。
仍然会把历史失败永久当当前失败。
先修 expression,再用 for 处理持续性。
scrape、evaluation 与 delay
假设:
“2m 后 page”不代表现实事件开始后精确两分钟:
可能更久。规则验收应测 end-to-end detection time,而不是只读 YAML。
VMAlert 支持 group eval_delay/query latency offset 等。取值要根据真实 ingestion
延迟,并在 rule test 与 dashboard query 中使用一致时间对齐。
recording 与 alert group 分离
VMAlert 一个 group 内顺序执行 rule,但 recording result 异步写回 remote storage。若同组后续 alert 立即读取前一个 recording result,可能看不到本轮 结果。
不要:
本章分成:
测试用 group_eval_order 先运行 recording groups,再运行 alert groups。
rule result limit
错误 label 可能让一条 rule 产生数十万结果。VMAlert group 支持 result limit; 生产应按预计 cardinality 设置并监控 exceeded error。
限制不是修复:
- 先保证 labels 有界;
- 再估算 series;
- 限制作为故障保护;
- 超限时 health unknown,不能默默丢结果;
- 监控 rule error。
Alertmanager group_by
本章:
没有把 ins 放进 user symptom grouping。原因:
组件信息在诊断包和 dashboard,下游 page 围绕服务事件。
group timing
含义大致是:
- group_wait:新组第一次通知前等待相关 alert 聚合;
- group_interval:组变化后再次发送的最小间隔;
- repeat_interval:持续 alert 重复提醒间隔。
取值要与 severity 匹配。SEV-1 等 30 秒可能可以,也可能太慢;真实策略需 notification SLO 和业务 owner 接受。
dedup identity 来自 labels
改变 label 会创建新 alert:
因此不要把高变化字段放 alert label。它们会:
- 重置
for; - 打破 dedup;
- 增加通知;
- 让 silence 失效。
inhibition 只去重,不删除事实
本章第一条:
它不会抑制:
- 不同 service;
- 不同 environment;
- freshness;
- correctness;
- monitoring path。
第二条:
它不抑制独立 blackbox 看到的 user symptom。
正确性永不被普通抑制
本章对抗测试会拒绝任何 target matcher 包含:
原因:
可以在 incident tooling 中关联同一事件,但不能静默正确性 page。
silence 与 inhibition 不同
inhibition 是配置中的关系规则;silence 是带 matcher 和期限的操作。
silence 必须:
- owner;
- reason;
- start/end;
- exact matcher;
- replacement observation;
- incident/change reference;
- review/expiry。
不要为了维护直接 silence 整个 cluster 的所有 alert。planned maintenance 也 不应从 SLO event 中事后删除。
recovery 与 flapping
恢复条件可以:
- expression 直接 false;
- 使用 hysteresis;
- 使用
keep_firing_for(若平台与政策采用); - 由 Alertmanager repeat/group timing 控制通知;
- 要求独立 verification。
不要只让 threshold 出现巨大滞后,导致真实恢复长时间仍 page。
测试至少覆盖:
25.4.3 每条告警绑定所有者、证据和首个安全动作
page 是打断权
page 会打断一个人的当前工作或睡眠。因此最低合同:
没有这些字段,报警不是“先上线再补文档”的半成品,而是潜在事故放大器。
route class
| route | 何时使用 | 例子 |
|---|---|---|
| page | 需要立即有人介入 | fast burn、correctness、monitoring path |
| ticket | 当前可排期但有 deadline/owner | capacity、slow reliability debt |
| diagnostic | 解释 symptom,不独立打断 | replica distance、CPU、pool queue |
| test | 尚未治理接受或只做演练 | latency candidate、archive candidate |
severity 不应与 component 数值机械绑定。
owner_function,不是个人名字
真实 Alertmanager route 再映射到当前值班表。好处:
- 人员轮换不改 rule;
- 服务责任与平台执行分开;
- 可以审查 role 是否可达;
- 可以测试 fallback escalation。
本章空 receiver 只是验证标签分支,未证明真实 on-call 可达。
首个安全动作要降低不确定性或损害
fast availability:
不是:
这些数据库动作可能扩大未知写结果。
freshness:
正确性:
monitoring path:
首个动作不是完整修复,而是事故中最不容易后悔的下一步。
evidence link 不能带 credential
source/dashboard URL:
不要:
receiver 中的 secret 也不能进入 Git。
annotation 要短而确定
通知首屏包含:
不要塞:
- 全部诊断 SQL;
- 数百行日志;
- 未经验证的 root cause;
- 变化的 error text;
- 密码/token;
- “请检查”这种无动作文本。
runbook 需要停止线
告警 runbook 不是:
它至少包括:
- entry condition;
- identity/target;
- authority;
- safe read-only queries;
- hypotheses;
- first action;
- stop condition;
- escalation;
- mutation approval;
- verification;
- evidence。
一个 page 若 runbook 第一条就是 destructive action,应退回评审。
dashboard 不负责结论
dashboard URL 负责定位:
- SLI windows;
- event count;
- release marker;
- entry/DB/host correlation;
- metamonitoring。
runbook 负责:
- 如何解释;
- 如何复核;
- 什么能做;
- 什么不能做。
Grafana panel 不能表达完整权限和停止线。
alert review expiry
第 24 章 candidate 带 expires_for_review。规则应定期检查:
- SLO target 是否变;
- metric/version 是否变;
- query cost;
- false positive/negative;
- page actionability;
- route ownership;
- runbook 是否可执行;
- last drill;
- label cardinality;
- notification receipt。
“从未触发”可能是服务稳定,也可能是规则永远不匹配。VMAlert 有 never-firing 检测思路,但仍要用合成测试证明。
actionless instance-down 为什么被拒绝
候选:
缺少:
- user impact;
- owner;
- runbook;
- first safe action。
一个 replica 可能计划下线且服务正常。替代:
这不是“不监控实例”,而是不把所有 component state 都升级为打断。
25.4.4 用演练验证告警,而不是等生产事故
规则需要单元测试
测试文件指定:
然后注入:
检查:
为什么不直接在在线 VMAlert 测
向在线 datasource/Alertmanager 发合成数据会:
- 污染 production-like time series;
- 触发真实 route;
- 创建 silence/incident confusion;
- 和现有规则相互作用;
- 难以证明完全清理。
本章使用 vmalert-tool:
这是 L1 ephemeral,不是 live deployment。
测记录规则的算术
输入:
期望:
工具实际查询 recording result,防止:
- selector 写反;
- 分母只算 good;
- label join 丢失;
- window 名与内容不一致;
- expression 语法只“看起来对”。
测 alert labels 和 annotations
测试不仅看 alertname,还看:
这样 candidate 被误改成 page,或 accepted rule 被误改成 proposed,会使测试或 validator 失败。
测 missing
输入:
期望:
不要用零 bad ratio 代替。
还应分别测试:
- expected traffic 为零;
- SLI fresh;
- exporter down;
- rule query error;
- independent probe fails;
- label rename。
测 route,不发送通知
Alertmanager sandbox receiver 只有名字:
没有:
amtool config routes test 根据标签离线解析 receiver。八个用例覆盖:
测 inhibition 的正反例
五个用例:
只测“应该抑制”不够;错误的 broad matcher 往往会吞掉最重要的告警。
测规则引擎本身
在线当前快照:
这是已有 Pigsty 规则,不包括本章 31 条候选规则;本章从未部署它们。
metamonitoring 还应观察:
- evaluation duration vs interval;
- missed iteration;
- datasource error;
- remote write error;
- notifier error;
- state restore;
- no-series/never-firing;
- data delay;
- result limit。
“当前无告警”不是通知测试
current alerts=0、notification failures=0 不能证明:
- route matcher 正确;
- receiver secret 有效;
- 外部服务接收;
- 值班人员可达;
- 升级路径工作。
真实 notification canary 要穿过:
本章没有权限触达真实 receiver,覆盖矩阵保持 real_receipt_canary=false。
变更后的最小测试矩阵
| 改动 | 必测 |
|---|---|
| expression | normal/threshold/below/above/missing |
| window | onset、pending、firing、recovery |
| labels | grouping、dedup、cardinality |
| route | expected sink、default、no real integration |
| inhibition | positive + must-not-inhibit |
| annotation | owner/action/runbook/dashboard |
| recording | exact arithmetic and labels |
| engine | dry run、unit、error metrics |
| deployment | canary、rollback、receipt;本章未执行 |
本节验收
你应当能说明:
- burn rate 如何由 objective target 计算;
- 14.4x 为什么只是 policy starting point;
- 两个窗口分别防什么问题;
- instance ratio 为什么不是 event ratio;
- latency rule 为什么只能走 proposed test;
- correctness 为什么没有 error budget;
for为什么不能修复错误 expression;- recording 与 dependent alert 为什么要分 group;
- group_by 为什么不默认带 instance;
- fast/slow/ticket 应如何抑制;
- metamonitoring 只能抑制哪些派生告警;
- page 最低要绑定哪些动作字段;
- synthetic rule test 与 offline route test 各证明什么;
- 为什么它们仍不能证明真实 pager delivery。
上一节:SQL 可观测基线 · 返回本章目录 · 下一节:Pigsty 可观测体系 · 查看全书目录 · 查看索引中心