2941 字
约 9 分钟
21
S16-A31 · 时间线的重建:一次故障到底从什么时候开始
2024-12-31
2026-11-10

复盘会上一份时间线写着"14:02 开始异常,14:35 恢复"。有人问了一句"你确定是 14:02 开始的吗",回答是"第一个告警是 14:02"。而用户的投诉记录里,最早的抱怨时间是 13:41。

告警开始的时间不是故障开始的时间,它只是"系统终于被看见"的时间。
这也解释了一个常见错位:复盘的讨论大多集中在"恢复用了多久",而改进空间大多在"发现用了多久"。恢复时间往往受限于技术动作(回滚、扩容),而发现时间受限于观测设计——后者更容易改。

而这两个时间的差,恰恰是发现能力的度量——它通常比恢复时间更值得优化。


1. 时间线的五种来源

来源 精度 偏差方向
用户投诉/客服工单 高(真实影响) 早于监控
业务指标(订单量、成功率) 中高 等于真实影响
资源指标(CPU、连接数) 中 可能早于或晚于
应用日志(错误、超时) 高 取决于采样
变更记录(发布、配置) 高(精确时刻) 只在有人为动作时

第一项与第三项的差是最有价值的信息:它说明"从影响发生到被监控发现"这段有多长。

这里有个统计上的陷阱:如果一天发 20 次版,那么任何时刻都距某次发布不到一小时。所以"故障前有发布"这件事的信息量,取决于发布频率,不取决于时间接近。

第五项要用作"嫌疑清单"而不是"结论":变更时刻与故障时刻接近只说明可疑,不说明因果。断言因果需要"回滚后恢复"或"同样条件下复现"。

2. 重建时间线的四步

步骤 动作
1 定锚点 找一个精度最高的时刻(如发布记录)
2 按来源分层 用户侧、业务侧、资源侧分别排
3 对齐时区与时钟 全部转 UTC 再比较
4 标注不确定性 每个时刻写精度

对齐时还要注意"夏令时":有过夏令时的地区,同一本地时间在一年内出现两次或不存在,于是按本地时间排序会得到错乱的顺序。全部转 UTC 能彻底避免这类问题。

第三项是最容易出错的技术细节:日志按本地时间、监控按 UTC、客服系统按用户时区,三者未对齐时会出现"故障发生在监控之后"这种物理不可能。

第四项是诚实性要求:"约 13:40"与"13:41:22"是不同的信息,混在一起会让读者以为所有时刻都同样精确。

// 重建后的时间线(每行带来源与精度)
13:41  ~ 客服收到首批投诉(精度:分钟,来源:工单系统)
13:44  ~ 下单成功率从 99.2% 跌到 71%(精度:分钟,来源:业务指标)
13:47  ~ 支付服务错误率升至 12%(精度:分钟,来源:APM)
13:52  ~ 连接池使用率达到 98%(精度:秒,来源:资源监控)
14:02  ! 首个 P1 告警触发(精度:秒,来源:告警系统)
14:06  ! 值班确认并开始排查(精度:分钟,来源:IM 记录)
14:31  ! 回滚支付服务 v2.31 → v2.30(精度:秒,来源:发布系统)
14:35  ! 成功率回到 99%(精度:分钟,来源:业务指标)
// 关键读数:影响开始 13:41 → 告警 14:02 = 21 分钟发现延迟

3. 发现延迟怎么算、怎么改

环节 可优化手段
影响发生 → 业务指标可见 缩短指标采集粒度
指标可见 → 告警触发 改阈值/改用 SLO 告警
告警触发 → 人确认 值班与通知链路
人确认 → 定位 缩短排查路径

第二项还有一个"方向"上的选择:症状告警(用户受影响)适合告警,原因指标(资源、队列)适合看板。把原因指标也做成告警,会得到大量"资源满了但用户没感觉"的噪音。

第一项常被忽略:业务指标按 5 分钟聚合,就注定有 5 分钟盲区。而很多团队只看资源指标(1 分钟粒度),于是"影响已经发生但资源正常"的故障完全看不见。

第二项的关键是从阈值告警转向"症状告警":阈值告警盯的是"某个数超了",症状告警盯的是"用户受影响了吗"。前者误报多、后者更贴近真实。

// 症状告警:直接盯用户可感知的结果
alert: checkout_success_rate
expr: rate(checkout_ok[5m]) / rate(checkout_total[5m]) < 0.95
for: 2m
severity: P1
annotations:
  summary: "下单成功率低于 95%(当前 {{ $value }})"
  runbook: "https://.../runbooks/checkout"
  # 关键:用业务结果而不是资源指标做判据

4. 时钟与对齐

问题 后果
主机时间漂移 跨机日志顺序错乱
时区混用 出现"负时间"
应用时间与采集时间不同 归因错位
精度的假象 毫秒值实际是秒级近似

第四项(精度假象)有个典型例子:日志时间精确到毫秒,但实际精度只有秒(因为时间戳来自秒级缓存的时钟源)。于是两条"相差 3ms"的记录,真实顺序可能是反的——用它做因果推断会得出错误结论。

第一项在多节点部署里普遍存在:NTP 未同步时,两台机器的日志可能差几十秒,而分布式追踪恰恰依赖跨机时间戳排序。所以"trace 里出现了子调用早于父调用"是时钟问题的典型信号。

第三项要区分两个时间:事件发生时间(应用写)与采集时间(代理写)。用采集时间做时间线,会把"日志积压"误读成"故障延后"。

时间线还有一个"下钻"技巧:从影响开始时刻往前推 15 分钟,看有什么变化。多数故障的起点与某个变更在同一窗口内,而"往前推"这个动作能避免只盯着告警之后的时间。

// 变更与异常对齐:把最近 3 小时的发布/配置变更列出来
git log --since="3 hours ago" --pretty='%h %ad %s' --date=iso
kubectl rollout history deploy/pay -o json | jq -r '.items[-5:][] | "\(.revision) \(.changeCause)"'
// 与时间线的锚点对齐,逐条判断"时间接近且因果可信"

5. 时间线在复盘里的用法

用法 说明
定位决策点 哪些时刻做了判断、依据是什么
量化延迟 发现、响应、恢复三段
暴露信息断点 哪一段"没人知道发生了什么"
支撑改进项 每个改进对应一个延迟

第三项最有价值:时间线里出现"空白段"时,通常对应"没人知道该看什么"。这一段是流程或观测的缺口,而不是运气不好。

第四项要求每个改进项挂在一个具体延迟上,否则改进会变成"加强监控"这类无法验收的口号。

落地的记录载体也要固定:时间线应当写在故障单里,而不是散在 IM 聊天记录。因为复盘时需要所有人看同一份,而聊天记录的顺序会被消息插入打乱,也不便标注精度。

// 故障单里的时间线表(五列,可追加)
时刻(UTC)  事件                    来源        精度   备注
13:41      首批投诉                 工单系统    分钟   影响起点
14:02      首个 P1 告警             告警系统    秒     =
14:31      回滚 v2.31→v2.30         发布系统    秒     变更
14:35      成功率恢复               业务指标    分钟   恢复判据

6. 排错:五种"时间线不可信"

现象 成因 处理方向
故障晚于恢复 时区未对齐 全部转 UTC
告警早于影响 资源指标先动 区分症状与原因
相邻事件顺序颠倒 时钟漂移 检查 NTP
找不到起点 只有告警记录 补业务指标与投诉
各人回忆不一致 无统一记录 以系统记录为准

第三项(空白段)还应当反向使用:如果某一整段都"没人知道",那这段应当出现在改进清单的第一条,因为它是下一次故障里最容易重复的部分。

第五项是复盘常见冲突源:人的回忆会被事后信息污染(知道了原因就会"记得"当时已经怀疑它)。所以时间线应当以系统记录为主,人的回忆只用于补充"当时在想什么"。

时间线还有一条容易漏的"末端":恢复不等于"用户不再受影响"。技术上恢复(成功率回到基线)之后,客服仍在处理积压工单、退款仍在批量处理——这些"尾巴"对用户的影响可能持续数小时,而它通常不进时间线。

// 时间线的三个端点,不止两个
影响开始 ─── 技术恢复 ─── 用户感知恢复 ─── 后续清理完成
 13:41        14:35          16:10            次日 10:00
// 只写"开始—恢复"会漏掉后两个端点,复盘时低估影响时长

7. 边界:什么情况不必精细重建

场景 为什么 做法
影响极小(个别用户) 成本高于收益 记结论即可
原因已明确且无争议 无需时间线 直接写改进
单一组件、单点故障 时间线天然清楚 简要记录
演练而非真实故障 时间线由脚本决定 记脚本耗时

最后一条与"记录成本"有关的边界:时间线不必写到完美,但要写到"能支撑三个数字"——影响开始时间、告警时间、恢复时间。其余细节可以在需要时再补,这三个是复盘的最小骨架。

判断口径一句话:这次复盘要不要回答"为什么没早点发现"。要,就必须有时间线(且必须有用户侧来源);不回答,时间线只是叙事装饰。


8. 自测

  1. 为什么"告警时间不是故障开始时间"?这个差值度量的是什么能力?
  2. 变更记录为什么只能当"嫌疑清单"而非结论?断言因果需要什么证据?
  3. 重建四步里,哪一步最容易出错?"标注不确定性"为什么是诚实性要求?
  4. 发现延迟分四段,哪一段最常被忽略?为什么业务指标按 5 分钟聚合会造成盲区?
  5. 为什么"时间线里的空白段"最有价值?改进项为什么必须挂在一个具体延迟上?
  6. 判断"是否需要精细重建"的那个问题是什么?
S16-A31 · 时间线的重建:一次故障到底从什么时候开始
https://www.clxhxhhr.top/posts/6481/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。