语法正确,告警却错了
目标
亲手修改记录规则和告警规则,编写涵盖正常、重置、缺失和等待时间的测试,以检测语义错误。
为什么重要
语法正确不等于语义正确。只使用正常数据或空测试时,错误规则也可能通过。 本实验使用固定版本 Prometheus 3.14.0 的真实 promtool 和合成时间序列。 不会修改生产 LabHub 或外部 Prometheus 的配置、实际抓取目标及 Alertmanager。 实验时长为 55 分钟。如有需要,请在到期前延长。会话结束时,VM 和学员文件将被回收。
已准备的文件和命令
工作目录是 /root/pca-rule-lab。以下步骤中的所有文件名均相对于该目录。 materials/inputs.json 是固定输入,materials/expected.json 是完整预期结果。 materials/starter-文件名 是包含故意错误的起点。请将相应文件复制到工作目录,保持文件名不变, 然后进行编辑。不要覆盖已安装的材料文件。三份规则文件彼此独立,因此后续步骤的修改 不会清除前面步骤的答案。不要根据材料和示例猜测答案,应与正文中的契约比较。
python3 /opt/fixtures/pca_rule_lab.py complete N 会检查当前答案,并在 observation-N.json 中 保存语法、语义检查结果和输入哈希。如果失败,请比较输出中的 exp 与 got,修改答案后重新执行。 grade N 会重新运行真实引擎,但不会修改答案和观测结果。prepare N 只会补齐之前的步骤。 solve N 用于查看答案,只创建尚不存在的答案,不会覆盖已有的部分答案。 answer N 只在终端输出答案内容。可以将部分答案与其比较并自行修改。 测试文件中的 rule_files 应只保留 rules.json。辅助程序会把当前步骤的规则移到临时副本的 rules.json 中, 然后执行 promtool check rules 和 promtool test rules。无需在学员目录中创建 rules.json。 JSON 是 YAML 的一种有效表示,也可以直接编写 YAML。输入、查询、时间点和预期值是固定的练习契约, 但测试顺序、输入顺序、样本顺序及空白可以不同。规则表达式通过结果进行检查。 请保留 starter 中的一个组、三条记录规则和一条告警,以及名称、顺序、间隔和标签。 附加规则、模板、外部文件及 YAML 别名不在本练习范围内。文件必须采用 UTF-8 编码,且不超过 64KiB。
步骤
- 在 diagnosis.json 中写入布尔值 syntax_proves_semantics=false、normal_data_sufficient=false,以及数值 reset_good_rate=10.75、reset_bad_rate=10,然后执行 complete 1。在 observation-1.json 中比较同一条错误聚合规则的语法检查成功、正常数据测试成功和重置反例测试失败。
- 将 materials/starter-rate-rules.yml 复制为 rate-rules.yml,并修正 pca:requests:rate5m 的 expr。先按原始序列计算 rate,再按 route 求和;正常数据在第 6 分钟应得到 /checkout=11、/status=2,重置场景在第 6 分钟应得到 /checkout=10.75。保留其余规则、组、1m 间隔和标签,然后执行 complete 2。
- 将 materials/starter-reset-tests.yml 复制为 reset-tests.yml,并把 masked-counter-reset 在第 6 分钟的预期请求率从 10 改为 10.75。对照 materials/expected.json 检查两个场景的输入、查询、标签及其余预期值。complete 3 会同时检查学员规则能够通过,并确保聚合顺序错误和丢失 route 的错误答案无法通过。
- 将 materials/starter-coverage-rules.yml 复制为 coverage-rules.yml。从 pca:requests:ready_rate5m 的 expr 中删除用 0 填补不存在路径的部分,只保留当前 count by(route) 为 2 的路径。显式 stale 时不应有 /checkout 结果,而实际无请求时应存在值 0。保留 /status=2,然后执行 complete 4。
- 将 materials/starter-coverage-tests.yml 复制为 coverage-tests.yml。从 missing-is-not-zero 在第 6 分钟的 ready_rate5m 预期样本中移除 /checkout=0。保留 real-zero 的 0 样本。还要保留 missing-sample-is-not-staleness 的当前数量 2、样本年龄 60 秒和请求率 11,然后执行 complete 5。不要把当前时间序列数量解释为新鲜度保证。
- 将 materials/starter-alert-rules.yml 复制为 alert-rules.yml,并为 PcaHighRequestRate 设置 for: 2m。保留受保护的 expr:rate > 10.5,以及 severity=practice。正常数据应在第 5、6 分钟处于 pending,第 7 分钟进入 firing;第 6 分钟发生 stale 后,则应在第 7、8 分钟处于 pending,第 9 分钟进入 firing。执行 complete 6,检查全部 6 个场景。
- 将 materials/starter-alert-tests.yml 复制为 alert-tests.yml。把 gap-restarts-pending 在第 7 分钟的 firing 告警预期值改为空 exp_alerts。保留第 9 分钟触发,以及对 ALERTS 的 pending、无告警、firing 检查;也保留简单样本缺失时第 7 分钟触发的检查。complete 7 还会检查缺少 for、for 为 1 分钟、for 为 3 分钟及缺少保护条件这四种错误答案。
- 在 report.json 中写入布尔值 missing_is_zero=false、count_proves_freshness=false、notification_delivery_tested=false、production_scraping_tested=false,以及字符串 stale_gap_fires_at="9m"、missing_sample_fires_at="7m"。通过 complete 8 重新验证规则、测试契约和之前步骤的观测结果。不要声称已经验证了实际告警投递或生产环境 scrape。
参考与限制
这些结果基于从初始值 0 开始的合成输入和 1 分钟评估间隔。由于包含 5m 窗口的边界外推,修改输入后 不要仍然期待相同的数值。/checkout 的 a 重置时,b 仍在持续增长,/status 是独立的对照路径。 显式 stale 与单纯缺失样本是两种不同的输入。count=2 并不保证样本新鲜度或实例身份。 等待时间采用虚拟评估时间,无需实际等待 9 分钟。pending 和 firing 也会通过 ALERTS 标签进行检查。 确认告警进入 firing 并不等于确认外部告警已经送达。本测试不包含实际 scrape 的网络行为。 材料哈希用于发现意外覆盖及混用其他实验的观测结果,并不能作为 防止同一 VM 上 root 篡改所有代码的安全保证。评分预算为 60 秒,准备预算为 90 秒,引擎还有更短的限制。 官方规则测试文档
划分语法检查与语义检查的职责
在 diagnosis.json 中写入布尔值 syntax_proves_semantics=false、normal_data_sufficient=false,以及数值 reset_good_rate=10.75、reset_bad_rate=10,然后执行 complete 1。在 observation-1.json 中比较同一条错误聚合规则的语法检查成功、正常数据测试成功和重置反例测试失败。
观察同一条规则面对不同输入时会产生什么结果。
编写不掩盖重置的记录规则
将 materials/starter-rate-rules.yml 复制为 rate-rules.yml,并修正 pca:requests:rate5m 的 expr。先按原始序列计算 rate,再按 route 求和;正常数据在第 6 分钟应得到 /checkout=11、/status=2,重置场景在第 6 分钟应得到 /checkout=10.75。保留其余规则、组、1m 间隔和标签,然后执行 complete 2。
如果先求和再计算 rate,可能会丢失原始序列的重置信息。
编写能够拒绝错误聚合的测试
将 materials/starter-reset-tests.yml 复制为 reset-tests.yml,并把 masked-counter-reset 在第 6 分钟的预期请求率从 10 改为 10.75。对照 materials/expected.json 检查两个场景的输入、查询、标签及其余预期值。complete 3 会同时检查学员规则能够通过,并确保聚合顺序错误和丢失 route 的错误答案无法通过。
如果为了迎合实现而降低预期值,测试就会放过错误规则。
编写区分缺失测量与真实零值的规则
将 materials/starter-coverage-rules.yml 复制为 coverage-rules.yml。从 pca:requests:ready_rate5m 的 expr 中删除用 0 填补不存在路径的部分,只保留当前 count by(route) 为 2 的路径。显式 stale 时不应有 /checkout 结果,而实际无请求时应存在值 0。保留 /status=2,然后执行 complete 4。
当前没有样本与存在值为 0 的样本是两种不同状态。
在测试中记录缺失与新鲜度边界
将 materials/starter-coverage-tests.yml 复制为 coverage-tests.yml。从 missing-is-not-zero 在第 6 分钟的 ready_rate5m 预期样本中移除 /checkout=0。保留 real-zero 的 0 样本。还要保留 missing-sample-is-not-staleness 的当前数量 2、样本年龄 60 秒和请求率 11,然后执行 complete 5。不要把当前时间序列数量解释为新鲜度保证。
通过 timestamp 检查前一个样本是否仍会在 lookback 范围内被选中。
设置告警触发前后的时间边界
将 materials/starter-alert-rules.yml 复制为 alert-rules.yml,并为 PcaHighRequestRate 设置 for: 2m。保留受保护的 expr:rate > 10.5,以及 severity=practice。正常数据应在第 5、6 分钟处于 pending,第 7 分钟进入 firing;第 6 分钟发生 stale 后,则应在第 7、8 分钟处于 pending,第 9 分钟进入 firing。执行 complete 6,检查全部 6 个场景。
还应检查触发前一刻的状态,以发现过早触发。
测试中断后的等待是否重新开始
将 materials/starter-alert-tests.yml 复制为 alert-tests.yml。把 gap-restarts-pending 在第 7 分钟的 firing 告警预期值改为空 exp_alerts。保留第 9 分钟触发,以及对 ALERTS 的 pending、无告警、firing 检查;也保留简单样本缺失时第 7 分钟触发的检查。complete 7 还会检查缺少 for、for 为 1 分钟、for 为 3 分钟及缺少保护条件这四种错误答案。
条件因 stale 中断后,for 会从条件恢复的时刻重新计时。
同时重新验证规则和测试并报告范围
在 report.json 中写入布尔值 missing_is_zero=false、count_proves_freshness=false、notification_delivery_tested=false、production_scraping_tested=false,以及字符串 stale_gap_fires_at="9m"、missing_sample_fires_at="7m"。通过 complete 8 重新验证规则、测试契约和之前步骤的观测结果。不要声称已经验证了实际告警投递或生产环境 scrape。
报告时,请区分测试中确认的状态与外部系统的行为。