TT Lab
博客 开始
学习 学习路径 课程

故障指挥与复盘

影响估算

在 TT Lab 中继续学习

一句话总结

“有多少人受到影响”不是数日志的问题,而是定规则的问题。只有先定好去掉什么(健康检查、机器人、内部流量)、把什么 合并为一(重试、同一个人的多个会话)、统计哪段时间(带时区的区间),数字才会收敛为一个。

为什么需要它

一出事故,同一个问题会冒出三个数字。状态页团队说“4 千次请求失败”,客服团队说“172 名用户”, SRE 团队说“80 名”。三者都是从同一份日志数出来的,也都不是算错了,只是规则不同。通告中只能发出一个, 而赔偿、监管报告、SLO 计算都会直接使用这个数字。写得太大,会带来不必要的赔偿和信任受损;写得太小,就成了隐瞒。

它如何工作

第一,去掉噪声。 Kubernetes 的健康检查(/healthz、/readyz)在故障中反而失败得更多,搜索引擎机器人和公司内部的 合成监控也不是用户。要按路径、User-Agent、内部网段(如 10.0.0.0/8)来区分。

第二,把重试合并为一。 客户端失败后会重试。同一请求 id 的行是一个请求,用户经历的 结果是最后一次尝试。如果第一次尝试失败、重试成功,那个请求就不算失败(只是慢了)。按行计数,失败就会 被夸大;按“只要失败过一次”计数,失败的用户就会被夸大。

第三,统计人。 失败请求数不是用户数。一个人会失败多次。已登录的人即使打开多个设备和会话, 也是一个人;未登录的访问只能把一个会话算作一个人(所以这个数字更接近“至少有这么多”)。

第四,定好区间和分母。 区间要用带时区的时刻来传递——把“从 14:10 开始”读成 UTC,就会统计相差九个小时的 另一个区间。错误率是同一规则下的失败 ÷ 请求,要与平时的错误率并列才有意义。受影响的用户也 要连同该区间的活跃用户一起写出来,才能看出规模。

最后,把规则留成代码。 手工数出的数字,下次事故还得再手工数,而且每个人又会不同。

在同一份日志上逐条违反规则,数字就会这样分岔(以一套实验素材统计的例子)。

计算方式 受影响用户 错在哪里
按规则 99 —
保留健康检查、机器人、内部网段 118 混入了不是用户的请求
重试中只要失败过一次就算失败 172 把靠重试成功的人也算进去了
直接使用失败请求数 117 把一个人的多次失败算成多人
丢掉区间的 +09:00 0 统计的是九个小时之后

可怕的是,只看一个数字,哪个都不显得奇怪。所以很多团队会在通告中连同数字写下一行得出该数字的规则(去掉了 什么、合并了什么)——让下一个人能用同样的规则重新统计。

现场遇到的情形

三个团队的数字不同时,要做的不是争论谁对,而是把规则逐条对照。状态页脚本 没有去掉健康检查,客服脚本把重试中的第一次失败算作失败,还有一个把区间读成了 UTC—— 这些差异,只要把脚本对齐到同一规则就会消失,剩下同一个数字。

未登录的访问有局限。同一个人换了浏览器,会话就变成两个,被算成两个人;反过来,共享 设备会把多个人算成一个人。所以匿名访问多的服务会像“受影响用户至少 N 名(按登录计 M 名)”这样 把两者分开写。无论哪种,关键都是不隐藏规则。

数字要与分母一起读。“99 名”是在该区间活跃的 372 人中的 99 名,还是 3 万人中的 99 名,完全是两种不同的 事故。错误率也要与平时的错误率并列才能看出大小——平时 0.4% 变成了 9%,就是二十倍;平时 8% 变成了 9%,可能就算不上事故。使用 SLO 的团队,这些数字会直接成为错误预算的消耗量。 只有用同一规则统计的请求和失败来扣减预算,到季度末才能把“这次事故用掉了预算的百分之几”与其他事故比较。

最后,影响数字在事故过程中会多次变化。第一份通告中的数字是到那个时刻为止的值,事故结束后复盘中的 数字是整个区间的值。两者不同是正常的,只要守住两个数字都出自同一规则即可。 所以每份通告都要一并写明“截至几点”——没有基准时刻的数字,日后无论谁重新统计都对不上。

接下来的实验要做什么

从支付故障的访问日志中过滤掉健康检查、机器人和内部流量,合并重试,统计请求、失败和错误率,并按规则统计受影响 用户。把这套规则做成脚本,确认它对从未见过的日志也正确;最后修好数字各不相同的三个团队的 脚本。