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

故障指挥与复盘

支付事故频道——谁在指挥,哪里出现了空缺

在 TT Lab 中继续学习

目标

从事故频道记录(聊天、呼叫、订单)中用数据找出角色的流转、宣布所需的时间、没有负责人的决定,并用算出的数字 按固定格式撰写情况通告。最后,在配置中修好呼叫没有触达人的故障事件。

为什么重要

事故指挥不是“要做好”的决心,而是可以用记录来确认的习惯。宣布花了几分钟、IC 有没有动手、 没有负责人的决定有几个,都原样留在频道记录中,只有去统计它们的团队才会在下一次进步。情况通告中的数字 是客户和管理层会照单全信的值,所以不能凭估计来写。而这一切都要从呼叫触达人开始—— 呼叫配置几乎是唯一可以在事故发生之前就修好的指挥装置。

步骤

  1. 用 python3 /opt/fixtures/ic/ickit.py open roles 展开支付事故素材,阅读 /root/ic/roles/README.txt。统计在事故频道(chat.jsonl)中发过言的人数(排除机器人 icbot,同一个人只算一次),以一个数字写入 /root/ic/roles/answers/participants.txt。
  2. 计算从这起事故的首次告警(pages.csv 中名称以 pay- 开头的告警首次 triggered 的时刻)起,到 (1) 首次响应(pay- 告警的首次 acked)、(2) 频道中的 /declare 分别花了多少秒,以 ack_delay_sec=<seconds>、declare_delay_sec=<seconds> 两行写入 /root/ic/roles/answers/declare.txt。
  3. 把事故结束时(/resolve)IC、Comms、Ops 分别由谁担任,以 ic: <name>、comms: <name>、ops: <name> 三行写入 /root/ic/roles/answers/roles.txt(名字不带 @)。
  4. 找出 IC 在担任指挥的那段时间里亲自敲了 /doing 的决定,把决定编号(D1 形式)每行一个写入 /root/ic/roles/answers/ic-hands.txt(如果没有这样的决定,写 none)。交出 IC 之后,原 IC 所做的事不算在内。
  5. 在用 /decide 记录的决定中,找出 (1) 没有用 /own 确定负责人的,以及 (2) 在前一个人 /done 之前,另一个人对同一决定 /doing 的(同时动手的),以 unowned: <decisions>、concurrent: <decisions> 两行写入 /root/ic/roles/answers/work.txt(没有的话,冒号后面留空)。
  6. 以 Comms 敲下 /status 的时刻为准,把第一份情况通告写成五行存入 /root/ic/roles/answers/status.txt。第一行是 [SEV<n>] <title> — status update(严重程度和 /declare 的标题),接着是 time: <YYYY-MM-DD HH:MM> KST(通告时刻,精确到分)、impact: failed_orders=<N> affected_customers=<M> since=<HH:MM> KST(失败订单数、这些订单的客户数、首次告警时刻)、command: ic=@<name> comms=@<name>(通告时刻的 IC 和 Comms)、next_update: <YYYY-MM-DD HH:MM> KST(在 README 规定的按严重程度的间隔之内)。影响数字从首次告警时刻到通告时刻之间的 orders.csv 中统计。以韩文写键的旧格式也会被接受。
  7. 运行 incident ic-slow-page 会触发故障事件。昨晚 payments、search、identity 三个团队的告警各响了一次,但三者在最初 20 分钟里都没有呼叫到任何人(呼叫记录:/var/log/pager/pages.log,配置:/srv/pager/,模拟器:python3 /opt/fixtures/ic/pagersim.py <alert> <time>)。为每个团队找出原因并修好,使其无论何时响起,都能在 0 分钟呼叫到该团队的值班人。策略的第一级设为在 0 分钟呼叫该团队的值班人(oncall),不能把一周值班的 60% 以上压在一个人身上,也不能删除 people.csv 中的人。值班人从事件发生前 people.csv 中登记在该团队的人中指派(不新建人员,也不恢复离职者)。联系方式必须是呼叫服务能使用的 sms:<number>、voice:<number>、push:<id>、email:<address> 形式;修复路由规则时不要改动原有规则,而是追加(原名称的告警也必须继续路由到该团队)。在 /root/incident/ic-slow-page/report.txt 中写下 payments: <code>、search: <code>、identity: <code> 三行以及 evidence: <pages.log-line>。每个团队的代码是以下之一:ack-timeout(呼叫触达了,但确认太慢)、contact-missing(值班人的联系方式为空)、override-departed(值班替班指向离职者)、route-mismatch(告警名称与路由规则不符,落入默认策略)、schedule-gap(值班表没有覆盖那个时刻)。

参考

展开素材——频道里有谁

用 python3 /opt/fixtures/ic/ickit.py open roles 展开支付事故素材,阅读 /root/ic/roles/README.txt。统计在事故频道(chat.jsonl)中发过言的人数(排除机器人 icbot,同一个人只算一次),以一个数字写入 /root/ic/roles/answers/participants.txt。

一行就是一个 JSON。用 jq 只提取 user 栏,去重后计数。机器人不是人。

从首次告警到响应、宣布

计算从这起事故的首次告警(pages.csv 中名称以 pay- 开头的告警首次 triggered 的时刻)起,到 (1) 首次响应(pay- 告警的首次 acked)、(2) 频道中的 /declare 分别花了多少秒,以 ack_delay_sec=<seconds>、declare_delay_sec=<seconds> 两行写入 /root/ic/roles/answers/declare.txt。

两个文件的时区不同(pages.csv 是 UTC,聊天是 KST)。换算成同一时刻单位后再相减。pages.csv 中还先出现了与这起事故无关的告警。date -d 两种形式都能读。

事故结束时的角色

把事故结束时(/resolve)IC、Comms、Ops 分别由谁担任,以 ic: <name>、comms: <name>、ops: <name> 三行写入 /root/ic/roles/answers/roles.txt(名字不带 @)。

按 README 中的命令规则统计——只有以 / 开头的消息才是命令,同一角色再次指派就是交接。机器人的复述、写在句子中的命令、被机器人拒绝的角色,都不算角色变更。

IC 亲自动手的决定

找出 IC 在担任指挥的那段时间里亲自敲了 /doing 的决定,把决定编号(D1 形式)每行一个写入 /root/ic/roles/answers/ic-hands.txt(如果没有这样的决定,写 none)。交出 IC 之后,原 IC 所做的事不算在内。

频道是按时间排序的。从上往下读,用一个变量记住“现在的 IC 是谁”,再与敲 /doing 的人比较。

没有负责人的决定与重叠的工作

在用 /decide 记录的决定中,找出 (1) 没有用 /own 确定负责人的,以及 (2) 在前一个人 /done 之前,另一个人对同一决定 /doing 的(同时动手的),以 unowned: <decisions>、concurrent: <decisions> 两行写入 /root/ic/roles/answers/work.txt(没有的话,冒号后面留空)。

要为每个决定记住“现在是谁在做”。前一个人做完之后为了确认再做一次的,不算重叠。awk 的关联数组或 python 的 dict 比较方便。

撰写第一份情况通告

以 Comms 敲下 /status 的时刻为准,把第一份情况通告写成五行存入 /root/ic/roles/answers/status.txt。第一行是 [SEV<n>] <title> — status update(严重程度和 /declare 的标题),接着是 time: <YYYY-MM-DD HH:MM> KST(通告时刻,精确到分)、impact: failed_orders=<N> affected_customers=<M> since=<HH:MM> KST(失败订单数、这些订单的客户数、首次告警时刻)、command: ic=@<name> comms=@<name>(通告时刻的 IC 和 Comms)、next_update: <YYYY-MM-DD HH:MM> KST(在 README 规定的按严重程度的间隔之内)。影响数字从首次告警时刻到通告时刻之间的 orders.csv 中统计。以韩文写键的旧格式也会被接受。

orders.csv 的时间是 KST,却没有时区标注——要与首次告警(UTC)比较,就得换算到同一时区。客户数要去重计数。角色只反映到通告时刻为止的 /role。

故障事件——三个告警在 20 分钟里没能叫醒任何人

运行 incident ic-slow-page 会触发故障事件。昨晚 payments、search、identity 三个团队的告警各响了一次,但三者在最初 20 分钟里都没有呼叫到任何人(呼叫记录:/var/log/pager/pages.log,配置:/srv/pager/,模拟器:python3 /opt/fixtures/ic/pagersim.py <alert> <time>)。为每个团队找出原因并修好,使其无论何时响起,都能在 0 分钟呼叫到该团队的值班人。策略的第一级设为在 0 分钟呼叫该团队的值班人(oncall),不能把一周值班的 60% 以上压在一个人身上,也不能删除 people.csv 中的人。值班人从事件发生前 people.csv 中登记在该团队的人中指派(不新建人员,也不恢复离职者)。联系方式必须是呼叫服务能使用的 sms:<number>、voice:<number>、push:<id>、email:<address> 形式;修复路由规则时不要改动原有规则,而是追加(原名称的告警也必须继续路由到该团队)。在 /root/incident/ic-slow-page/report.txt 中写下 payments: <code>、search: <code>、identity: <code> 三行以及 evidence: <pages.log-line>。每个团队的代码是以下之一:ack-timeout(呼叫触达了,但确认太慢)、contact-missing(值班人的联系方式为空)、override-departed(值班替班指向离职者)、route-mismatch(告警名称与路由规则不符,落入默认策略)、schedule-gap(值班表没有覆盖那个时刻)。

方向:呼叫要触达人,依次经过路由 → 团队策略的级别 → 那个时刻的值班人(轮换表优先于值班表)→ 那个人是否存在及其联系方式。每个团队断在哪一格各不相同。 工具:pages.log 中的 FAILED 和 route 行、模拟器(输入任意时刻预先跑一跑)、grep、awk -F,。 具体:为每个团队读出事件时刻的路由行和 level=1 行,再在这些行所指的文件(routes、people、overrides、schedule)中找到那个时刻、那个人的行。修好之后,不仅用那个时刻,还要用一周中的其他时刻运行模拟器。