CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
可观测性入门/课时/监控与告警
RawBlame
课时目录12 节

可观测性入门

  1. 01可观测性三支柱
  2. 02指标与 SLI
  3. 03结构化日志
  4. 04分布式链路追踪
  5. 05插桩与埋点
  6. 06监控与告警
  7. 07遥测与 OpenTelemetry
  8. 08Spring 可观测性
  9. 09SLO 与错误预算
  10. 10仪表盘设计
  11. 11故障排查流程
  12. 12综合练习

监控与告警

monitoring 节点;阈值与 on-call。

30 分钟

监控与告警

这一课你将能做到

  1. 区分 基础设施告警、Symptom(症状)告警 与 Cause(原因)告警,并解释为什么判题接口的 5xx 告警比单机 CPU 告警更适合叫值班
  2. 为 POST /api/judge/submissions 设计一条可执行的 Symptom 告警,含 PromQL 条件、持续时间、严重级别、runbook 链接
  3. 识别告警风暴的三种来源,给出治理动作,能解释「告警噪音 = 没有告警」

为什么要学

可观测性解决「有没有信号」;监控与告警 解决「什么时候该把人从床上叫起来」。信号再全,规则设计不好——瞬时抖动就叫、告警没有上下文、半夜几十条 Page 轰炸——团队会习惯性关闭通知,等于没有监控。

判题场景尤其敏感:比赛窗口高峰期,接口挂五分钟和单机 CPU 抖动五分钟对用户的含义完全不同。面试里「symptom 和 cause 的区别」「告警风暴怎么治」是高频题,本课结合 PromQL 和排障流程给答案。

先建立图像

类型示例(判题系统)响应方式
SymptomPOST /api/judge/submissions 5xx 率 > 1% 持续 5 分钟Page(立即叫醒)
Cause判题 worker 消费延迟增大、MySQL 连接池接近上限Ticket(工作时间处理)
Capacity磁盘剩余 < 15%、Kafka topic 分区扩容预警Ticket/计划处理
好的告警链路:

  SLI 越界(症状)──► Page on-call
       │
       ├─ Grafana 面板:确认影响面、时间线、最近发布
       ├─ Runbook 第一步:优先判断是否已自动降级
       └─ 日志/Trace:定位具体 submission 与代码路径

差的告警链路:

  单机 CPU 突升到 85% ──► 半夜 Page ──► 判题接口正常 ──► 告警被静音
       │
       └── 没有上下文、没有持续时间、没有恢复步骤

与 reliability-essentials 联动:告警文案应提示「是否已触发降级或熔断」。

跟着做

步骤 1:为判题接口写一条 Symptom 告警

先写意图,再给可运行的 PromQL:

# alert: JudgeSubmissionHighErrorRate
# 判题接口 5xx 率超过 1% 持续 5 分钟,这是用户可见的症状,直接 page
expr: |
  (
    sum(rate(http_server_requests_seconds_count{
      uri="/api/judge/submissions",
      status=~"5.."
    }[5m]))
    /
    sum(rate(http_server_requests_seconds_count{
      uri="/api/judge/submissions"
    }[5m]))
  ) > 0.01
for: 5m
labels:
  severity: page
annotations:
  summary: "判题提交接口 5xx 率过高"
  runbook: "https://wiki.internal/runbooks/judge-5xx"
  impact: "用户提交后无法得到结果或结果错误"
  first_check: "Grafana: http_server_requests RED 面板"

应得到:有 for(持续时间)、有 severity、有 runbook 链接、有 impact 说明——不是「expr 满足就 Ding 一声」。

步骤 2:把两条 Cause 告警降级为 ticket

1. 单机 CPU 持续 > 70%(非关键节点)
   → 原因:资源使用增加,用户可能完全无感知
   → 响应:工作时间 ticket,关注趋势而非瞬间

2. Kafka consumer lag 轻微增加但未超阈值
   → 原因:可能正在消费积压,用户仍能看到提交进入排队
   → 响应:ticket,先观察是否需要扩容 worker

应得到:Page 的标准是「用户此刻是否受伤」,不是「这台机器不舒服」。

步骤 3:为每条 page 告警补 runbook 四要素

JudgeSubmissionHighErrorRate 的 runbook:

1. 影响面:判题接口不可用,用户无法提交代码;关联 lesson/比赛需确认
2. 首要检查:
   - Grafana RED 面板:确认 rate、errors、duration 突变时间
   - /actuator/health:DB/Kafka 健康指示器状态
   - 最近发布/回滚记录
3. 止血开关:
   - 启用降级:返回静态提示页(如「判题队列繁忙,请稍后重试」)
   - 扩容:增加判题 worker 实例(如果 lag 是瓶颈)
   - 回滚:如果突变与某次发布时间吻合
4. 升级路径:
   - 5 分钟内未止血 → 叫 DBA 检查 MySQL 慢查询
   - 涉及大面积比赛中断 → 启动重大故障流程

应得到:收到告警的人,能在 30 秒内知道「哪里看」「先做什么」「什么时候升级」。

步骤 4:为「观测自身」加告警

# Prometheus 自身 scrape 失败
expr: up{job="coderoadmap-backend"} == 0
for: 2m
labels:
  severity: page
annotations:
  summary: "backend scrape 目标不可达"
  runbook: "https://wiki.internal/runbooks/scrape-failure"

避免「应用已挂但监控也瞎」的最坏情况。对照 prometheus-essentials 的 target health。

步骤 5:把 Spring Health 与告警分工写清

  • /actuator/health 供 K8s 探针(摘流/重启决策)和 值班看板
  • 用户向告警 仍以请求成功率为准,原因:health 红了但流量本身成功(非关键依赖挂了),或 health UP 但接口已经在报错(假 UP)

对照 sb-actuator。

步骤 6:模拟一次告警风暴并治理

场景:新部署引入了一个 NPE,导致 5xx 率飙升 30%。现有告警如下:

A. JudgeSubmissionHighErrorRate(page)     ← 该醒
B. KafkaProducerFailure(page)             ← 根因是 judge 失败,不是 Kafka
C. JudgeWorkerQueueLag(page)              ← 根因是 judge 失败,不是 lag
D. MySQLConnectionPoolHigh(page)          ← 可能是连锁反应
E. SinglePodRestart(page)                 ← 无关,Pod 是正常滚动更新

治理动作:

  1. 根源收敛:B、C、D 降级为 cause/ticket,不要跟主告警一起 page
  2. 依赖标注:B 的 runbook 写「先查上游 Judge 是否已报错,不要优先查 Kafka」
  3. 静默:比赛期间已知的短时压测峰值提前设静默窗口
  4. 聚合:同类 Pod 重启告警用聚合规则合并为一条

讲清楚要点

  1. 用户痛优先于机器忙,所以 Symptom 告警应高于纯资源告警——除非资源已直接表现为超时或失败。
  2. 瞬时抖动常见,所以告警要有持续时间(for)与聚合窗口——5 分钟内偶尔一次 502 不该 page。
  3. 没有上下文的叫醒等于噪音,所以每条 page 必须有 runbook,且 runbook 至少含影响面、首要检查、止血开关、升级路径。
  4. 人的注意力有限,所以告警要少而准——宁可先漏一次边缘 case,也不要每天噪音淹没真正的故障。
  5. 错误预算是决策工具,burn rate 多窗口告警比单阈值更贴 SRE 实践——见 obs-slo。
  6. 降级可能让错误率「看起来变了」,所以告警要理解业务降级语义——比如降级返回缓存数据不是 5xx,但用户得到的是旧结果,应有降级触发事件。
  7. K8s 探针失败会摘流,readiness 与告警、流量要一起设计——见 kubernetes-essentials。

你可能会懵的地方

  • Cause 告警是不是没用? 有用,但多数不应半夜 page。Cause 告警的价值在于:排障时提供线索、Symptom 出现前做容量计划、帮助定位根因。设成 ticket 级别,工作时间处理即可。

  • 为何「磁盘 85%」有时要升到 page? 如果该磁盘写满会导致服务全面不可用(如日志目录写满触发 OOM),可以定义为「即将发生的 Symptom」。但仍建议:带预测曲线 + 工作时间处理窗口 + 与真正的 Symptom 联动(接口延迟/错误率同步上涨时才是真 page)。

  • 告警和面板什么关系? 告警负责「叫醒」;面板负责「确认」和「关联」。值班流程应该是:告警 30 秒内打开 Grafana 确认影响面,然后按 runbook 查日志/链路。不要把 50 个面板阈值都变成 page——面板是给眼睛看的,告警是给 on-call 手机看的。

  • 和 prometheus-essentials 重复吗? 那门课教规则文件怎么写、Alertmanager 怎么分组路由;本课教 选什么告、如何分级、如何写 runbook——前者是「语法」,后者是「语义」。

错法对照

错法问题正解
CPU 一高就叫用户可能完全无感知,吵醒人对排障无帮助Symptom 优先;资源告警分级为 ticket
无 for 的瞬时阈值服务重启、网络抖动导致误报持续窗口 + 合理聚合(如 rate 5m)
告警无 runbookon-call 收到后不知道先看哪里每条 page 附影响面/检查项/止血/升级
上百条 page,团队全静音噪音淹没真实故障削减、合并、降级 severity、设静默窗口
只告应用,不告 scrape 失败监控自身挂了,应用故障也发现不了增加 up == 0 / scrape duration 告警

卡点急救

  1. 告警规则改了但不生效:先查 Prometheus 的 Status → Rules 是否加载了新规则;再确认 Alertmanager 的 route 匹配条件和标签是否一致;最后看 Alertmanager 的日志确认通知有没有被抑制或静默。
  2. 同一条告警反复触发/恢复(flapping):通常是阈值太紧或窗口太短。调整方向:增大 for 持续时间;把绝对阈值改成 rate 或 burn rate;增加 min 样本数防止数据稀疏时抖动。
  3. 告警发了但收不到通知:确认 Alertmanager 配置里的 receiver(钉钉/企微/邮件)连通性;确认路由 group_by 没有把所有告警吞掉;确认没有静默规则(silence)覆盖了该告警。

面试常问

  • Symptom 告警和 Cause 告警的区别?哪个优先? 背这个版本:Symptom 告警反映用户可见的问题,如判题接口 5xx 率上升——用户此刻在受伤,必须 page。Cause 告警反映根因线索,如 MySQL 连接池满——它可能导致症状,也可能不会;即使会,响应时间通常可以容忍。所以 Symptom 优先 page,Cause 处理为 ticket 或作为排障线索。核心原则:告警的对象是用户体验,不是机器状态。

  • 告警风暴怎么治理? 三来源:同源故障的多点告警(级联反应)、无效的低级告警(CPU/内存抖动)、配置错误(阈值太紧、窗口太短)。治理:按依赖关系把级联告警收敛为一条主 Symptom 告警;清理低级告警到 ticket 或删除;加持续时间 for 和最小样本数;设静默窗口应对已知的压测/发布;用 Alertmanager 的 group 和抑制规则减少重复通知。

  • 一条好的告警需要哪些要素? 四要素:明确的条件(PromQL 且可复现)、持续时间(for 防抖动)、严重级别(page/ticket/info)、上下文(runbook 含影响面、首要检查、止血开关、升级路径)。

自测三问

  1. 为什么「判题接口 5xx > 1%」通常比「某 Pod CPU 高」更适合 page?
  2. 一条 page 告警的 runbook 至少包含哪四要素?
  3. 假设判题服务崩溃导致 Kafka lag 上升、MySQL 连接池满、worker 重启,现有三条 page 告警,怎么治理?

小结一句话

监控求覆盖,告警求精准——Symptom 优先、带持续时间与 runbook,吵人的规则等于没有规则。

延伸

  • Prometheus:Alerting 概览
  • Google SRE Book:Alerting on SLOs
  • Prometheus Alertmanager:路由与抑制
  • 下一课《遥测与 OpenTelemetry》:统一插桩标准,一套 API 同时输出多后端。
加载本节练习…
← 上一课插桩与埋点下一课 →遥测与 OpenTelemetry