受影响的有多少人——按规则统计影响
目标
从支付故障的访问日志中过滤掉不是用户的请求,合并重试,按规则统计人,求出请求、失败、错误率、受影响 用户。把这套规则做成脚本,使其对从未见过的日志也正确;最后修好给出不同数字的三个团队的 脚本。
为什么重要
影响数字是情况通告、赔偿、监管报告、SLO 直接拿来使用的值。可即使是同一份日志,去掉什么、合并什么不同, 数字就会差好几倍。放入健康检查,故障看起来比实际大;把请求数当作人数,影响就被夸大;丢掉区间的 时区,就会统计错误的时间段。在争论“谁对”之前先对齐规则,并把规则留成代码,这就是这个实验的核心。
步骤
- 用
python3 /opt/fixtures/ic/ickit.py open impact展开素材,阅读/root/ic/impact/README.txt中的统计规则。把access.log中健康检查(路径恰好是/healthz或/readyz)的行数,以一个数字写入/root/ic/impact/answers/health.txt。 - 把从整个日志中去掉健康检查、机器人(User-Agent 中含 bot、crawler、spider,不区分大小写)、内部网段(客户端 IP 以 10. 开头)之后的行数,以一个数字写入
/root/ic/impact/answers/external.txt。 - 把事故区间(
window.txt,KST)内首次尝试落入其中的外部请求数,以及其中最后一次尝试状态为 500 以上的请求数,以requests=<n>、failed=<n>两行写入/root/ic/impact/answers/requests.txt(同一req的行是一个请求)。 - 按同一规则,以百分比(保留两位小数)计算事故区间的错误率,以及从日志开头到区间开始之前的平时错误率,以
error_rate=<percent>、baseline_rate=<percent>两行写入/root/ic/impact/answers/rate.txt。 - 把区间内至少有一个请求失败的人数,以及区间内发送过请求的人数,以
affected_users=<n>、active_users=<n>两行写入/root/ic/impact/answers/users.txt。人按user=统计,未登录的请求(user=-)把一个session=算作一个人。 - 让
/root/ic/impact/impact.sh <log> <start-iso> <end-iso>按 README 的规则输出requests=<n>、failed=<n>、affected_users=<n>三行(需要执行权限,语言不限——由第一行的 shebang 决定)。区间参数是2026-11-04T14:10:00+09:00形式。评分器会用这个实验的日志,以及当场新生成的其他日志和区间来运行它。 - 运行
incident ic-impact-dispute会触发故障事件。日志相同(/srv/impact/access.log)、区间相同(/srv/impact/window.txt),可/srv/impact/bin/statuspage、support、sre三个脚本的affected_users却各不相同。按 README 的规则修好这三个脚本,让三者都给出同一个真值(调用方式不变,直接写入数字会在其他日志上失败)。在/root/incident/ic-impact-dispute/report.txt中写下statuspage: <code>、support: <code>、sre: <code>三行以及evidence: <defective-line>。每个脚本的代码是以下之一:includes-probes(没有去掉健康检查、机器人、内部网段)、requests-as-users(把失败请求数当作人数)、retries-double-counted(重试中只要失败过一次就算失败)、sampling-gap(日志样本缺失)、sessions-as-users(已登录的人也按会话分别计算)、window-timezone(丢掉了区间时刻的时区)。
参考
- 素材工具:
python3 /opt/fixtures/ic/ickit.py open <name>会把素材展开到/root/ic/<name>/。素材用每个人不同的随机种子生成,评分器用同样的种子重新计算正确答案——别人的数字对不上。重新展开也是同样的素材,加上--fresh则从新的素材重新开始。 - 答案写在
/root/ic/<name>/answers/下。会话结束后就会消失,需要的话请另外保存。 - 事件工具:用
incident list查看可触发的事件及一行症状,用incident show <name>重新查看工单。再次触发同一事件,会用新的随机素材回到最初的故障状态(之前写的答案将不再正确)。 - 报告是
/root/incident/<name>/report.txt。每个对象写一行<target>: <cause-code>,最后原样附上evidence: <line>。证据必须是素材或观察记录中原样存在的一行(20 个字符以上)。评分器先看修好后的实际状态,报告用于确认你的判断。 - 日志的一行:
<utc-time> <IP> "<method> <path> <protocol>" <status> <bytes> "<User-Agent>" user=<id|-> session=<id|-> req=<id> attempt=<n>。 User-Agent 中有空格,只按空格切分,栏就会错位——用正则表达式或以引号分隔更安全。 - 区间比较要在带时区的时刻之间进行。python 的
datetime.fromisoformat能读+09:00,Z换成+00:00再放进去就能读。 - 两个常见错误——把行数当作请求数(重试重复),以及把失败请求数当作受影响的用户数。
展开素材——健康检查有几行
用 python3 /opt/fixtures/ic/ickit.py open impact 展开素材,阅读 /root/ic/impact/README.txt 中的统计规则。把 access.log 中健康检查(路径恰好是 /healthz 或 /readyz)的行数,以一个数字写入 /root/ic/impact/answers/health.txt。
请求行在引号内包含方法、路径、协议。按空格切分,路径是第四栏。
只留下外部用户的行
把从整个日志中去掉健康检查、机器人(User-Agent 中含 bot、crawler、spider,不区分大小写)、内部网段(客户端 IP 以 10. 开头)之后的行数,以一个数字写入 /root/ic/impact/answers/external.txt。
User-Agent 是用引号括起来的第二栏——以引号作分隔符(awk -F'"'),它就是第四栏。在整行中查找 bot,可能会匹配到其他栏。
区间内的请求与失败——重试合并为一
把事故区间(window.txt,KST)内首次尝试落入其中的外部请求数,以及其中最后一次尝试状态为 500 以上的请求数,以 requests=<n>、failed=<n> 两行写入 /root/ic/impact/answers/requests.txt(同一 req 的行是一个请求)。
日志是 UTC,区间是 KST。要为每个请求分别记住首次尝试的时刻和最后一次尝试的状态——用 python 的两个 dict 很方便。
错误率与平时错误率
按同一规则,以百分比(保留两位小数)计算事故区间的错误率,以及从日志开头到区间开始之前的平时错误率,以 error_rate=<percent>、baseline_rate=<percent> 两行写入 /root/ic/impact/answers/rate.txt。
错误率 = 失败请求 ÷ 请求 × 100。分母和分子必须是同一规则(外部请求、重试算一个请求)。是百分比(9.33),不是比率(0.09)。
统计受影响的人
把区间内至少有一个请求失败的人数,以及区间内发送过请求的人数,以 affected_users=<n>、active_users=<n> 两行写入 /root/ic/impact/answers/users.txt。人按 user= 统计,未登录的请求(user=-)把一个 session= 算作一个人。
失败请求数与人数不同。已登录的人即使有多个会话,也是一个人。
把规则写成脚本
让 /root/ic/impact/impact.sh <log> <start-iso> <end-iso> 按 README 的规则输出 requests=<n>、failed=<n>、affected_users=<n> 三行(需要执行权限,语言不限——由第一行的 shebang 决定)。区间参数是 2026-11-04T14:10:00+09:00 形式。评分器会用这个实验的日志,以及当场新生成的其他日志和区间来运行它。
把前面三步的计算汇集到一个接收参数的文件中即可。不要丢掉区间参数的时区标记。
故障事件——三个团队的影响数字各不相同
运行 incident ic-impact-dispute 会触发故障事件。日志相同(/srv/impact/access.log)、区间相同(/srv/impact/window.txt),可 /srv/impact/bin/statuspage、support、sre 三个脚本的 affected_users 却各不相同。按 README 的规则修好这三个脚本,让三者都给出同一个真值(调用方式不变,直接写入数字会在其他日志上失败)。在 /root/incident/ic-impact-dispute/report.txt 中写下 statuspage: <code>、support: <code>、sre: <code> 三行以及 evidence: <defective-line>。每个脚本的代码是以下之一:includes-probes(没有去掉健康检查、机器人、内部网段)、requests-as-users(把失败请求数当作人数)、retries-double-counted(重试中只要失败过一次就算失败)、sampling-gap(日志样本缺失)、sessions-as-users(已登录的人也按会话分别计算)、window-timezone(丢掉了区间时刻的时区)。
方向:三个脚本是从同一个模板分岔出来的。与 README 的五条规则逐条对照,每个脚本都会出现一处错位。 工具:diff(把两个脚本并排)、不用 python3 -X 也能用 print 查看中间值、前面步骤的 impact.sh。 具体:依次查看过滤条件(路径、User-Agent、IP)、选择最后一次尝试的那一行、收集人的数据类型(是集合还是列表,放进去的是什么)、读取区间参数的那一行。修好后用同样的参数运行三者,确认数字是否收敛为一个。