五列主值班/备援表让五个虚构名字轮转,每周两角色不同。重复四次覆盖 20 周;仅首周期第 2、5 周有虚构特殊标记。

排班需要连续覆盖,也需要复核实际负担

排班可以分配责任,但相同班次数量并不保证负担公平。应同时检查夜间告警、事故处理时间、恢复休息和可靠备援,而不只看每个人在表里出现了几次。 一份被共同承担的职责 值班是团队的事,不是某一位英雄的。轮班把「谁上次没睡好就谁来」变成一张明确的排班表、一套流程,让被打断分担到每个人头上,而不是让一个人独自背完一整条告警队列。而具体排班好不好,就在于「换人不换上下文」这六个字——交接若只换名字不换现状,同一个故障会在每次轮换时被重新发现一遍。所以轮班的灵魂不是「谁那天晚上在」,而是「责任与上下文如何平稳移交」。 交接是工作的一半 一次值班最容易断的,恰是交接这个环节。当接手的人从零开始、一片黑地接过来,本来该是交接的事就变成了重新破案。堵住这个缝只需要两样:一份书面交接(当前坏在哪、试过哪些、下一棒该试什么),以及一段重叠时间——让接班的人跟着旧的人一起盯岗,旧的人在正式放下前把现场讲完。一张只用来排名字的表,会一次次把同一个事故变成新事故。做出这套的难点,不在排满班,而在排完后还留得住上下文。 在铃声响起前演练 演练应安排在告警响起之前,而不是等故障发生。低峰期把 runbook 平铺地走一遍,练的是「恢复路径」而不是症状集;每一条 pager 都应映射到一份写好的计划,让雪夜里的铃声到来时,它是 checklist 而不是谜。提前练习可以增加团队在压力下的可靠选择;平静时候一遍遍过的常规动作,正是把「到时候再想」变成「按部就班照做」的地方。 坏掉的样子 单人长期值班看似省事,实则先压垮的是人。一个人连续几个月拿着寻呼机,即使没有告警也睡不踏实,看到通知就心慌,最后要么倦怠请辞,要么在一次深夜故障中彻底失手。谷歌站点可靠性工程指导强调人员配置与可持续工作负担。解法是设定单次值班上限,并保证下线周真正下线,上周的主值班不再兼任隐形备援。 升级链断裂是第二种常见死法。备援从不确认、联系方式过期,或者所谓升级到经理只是发进一个无人查看的邮箱,深夜三点主值班只能独自拆弹。升级链要像恢复流程一样演练:在工作时间实际寻呼一次备援,确认有人能在几分钟内应答,而不是只在通讯录里写个名字。 告警疲劳是第三种慢性失效。几百条噪声大、无法行动的告警教会团队寻呼机在说谎,于是唯一真实的那条也被顺手划掉。每条告警都应有负责人、有可执行的 runbook 链接、有经过上次误报调优后的阈值,无法行动的告警宁可降级为工单,也不要继续消耗信任。 交接缺失则让轮换只换名字不换上下文。周一换人时没有书面状态,周二就把周一的排查从零再做一遍。必须要求简短交接记录:当前症状、已尝试步骤、下一步动作,并在旧主值班真正下线前保留十五分钟重叠时间,把现场讲完再走。 每周都保留主值班与备援。 依据原文与明确限制静态绘制;未为本图重跑原文夹具。 快速验证 在正式发布排班前,可以先运行这个纸面模型。它为二十个连续星期安排虚构的主值班与备援,并保留两周虚构的特殊覆盖标记。标记不代表任何国家真实的公共假日,遇到标记也不会让整个服务无人负责。持续运行的服务,在某位工程师休假时仍需要明确接替,不能以节日为由直接删除那一周的覆盖。 把代码保存为空目录下的 rota_probe.py。 用 Python 3.9 或更新版本运行 python3 rota_probe.py;程序不访问网络或文件。运行时不要使用 -O、-OO 或非零的 PYTHONOPTIMIZE,以免断言被跳过。 核对逐周人员、各角色次数和最后的 PASS 行。 from collections import Counter from datetime import date, timedelta TEAM = ["ana", "ben", "cara", "dev", "elin"] # fictional names START = date(2027, 8, 2) WEEKS = 20 SPECIAL_WEEKS = {START + timedelta(weeks=1), START + timedelta(weeks=4)} rota = [(START + timedelta(weeks=i), TEAM[i % 5], TEAM[(i + 1) % 5]) for i in range(WEEKS)] assert len(rota) == WEEKS assert len({week for week, _, _ in rota}) == WEEKS assert all(primary != secondary for _, primary, secondary in rota) assert all(primary in TEAM and secondary in TEAM for _, primary, secondary in rota) assert all(b[0] - a[0] == timedelta(days=7) for a, b in zip(rota, rota[1:])) assert all(a[1] != b[1] for a, b in zip(rota, rota[1:])) primary_counts = Counter(primary for _, primary, _ in rota) secondary_counts = Counter(secondary for _, _, secondary in rota) assert set(primary_counts.values()) == {4} assert set(secondary_counts.values()) == {4} for week, primary, secondary in rota: marker = " special-coverage" if week in SPECIAL_WEEKS else "" print(f"{week}: primary={primary} secondary={secondary}{marker}") assert sum(week in SPECIAL_WEEKS for week, _, _ in rota) == 2 print("primary:", dict(sorted(primary_counts.items()))) print("secondary:", dict(sorted(secondary_counts.items()))) print("PASS: 20 covered weeks, distinct backup, four turns per role; special weeks remain staffed") 每一周都有不同的主值班与备援,包括两周特殊覆盖。每人分别获得四次主值班和四次备援,相邻两周的主值班也不同。本轮在 Python 3.12.14 中执行通过了这些断言。它们只证明表里明确检查的排班性质:星期没有缺口、两个角色不由同一人兼任,以及各角色计数相等。 ...

七月 16, 2027 · 2 分钟 · XB Field Notes