周五 17:20,群里有人问:这个小改动能上吗?
五分钟,没人回复。
17:25,他自己答:就一行,我上了。
17:31,他退出了群聊——不是主动的那种。
一、部署玄学博物馆
「周五不部署」不是一条规定,它是一整套民俗。散落在各个公司的版本包括:
- 只读星期五(Read-Only Friday):周五只读不写,上线窗口排在周二到周四;
- 节前冻结:圣诞节、春节、大促之前,变更冻结,谁提需求谁背锅;
- 看人下菜:老板出差前不部署、对外演示前一晚不升级、客户参观日只敢改文案;
- 物理玄学:机房放苹果、服务器上贴「已稳定运行 xx 天」、
sudo之前先深呼吸。
这些规矩好笑,但它们并不迷信。每一条都是用组织记忆硬编码出来的风险控制——每条规矩背后都躺着一次事故。真正值得追问的是:它们防的到底是「星期五」,还是别的东西?
二、把段子拆开:周五到底危险在哪
关键在这句:周五不会让代码更容易出错,它让错误更难被收拾。
- MTTR 变长。周三下午出事,值班的人五分钟就能进场;周五晚上出事,你得先等他放下筷子。
- 决策链变长。要不要回滚,得找审批的人;审批的人此刻在饭桌上,而回滚窗口是按分钟计价的。
- 变更规模变大。周五上的往往是攒了一周的合并——一周的改动挤进同一个窗口,一出问题,怀疑范围是整周。
- 注意力最低。周五下午的 review,
LGTM的含金量全年最低。
还有一个反直觉的数据:DORA / 《Accelerate》长期追踪的结论是,部署频率最高的团队,变更失败率反而更低。因为每次改动更小、更容易定位、回滚更快——「少发版更安全」是个错觉,「小步快发」才是解法。
所以「周五不部署」治的是症状。它把一个会痛的变更推到了周一,顺便让周一也变痛。
三、两个案例,日子都不是主角
CrowdStrike,2024 年 7 月 19 日,星期五。 04:09 UTC,一次 Falcon 内容更新(Channel File 291)下发,内核里的内容解释器越界读内存,全球约 850 万台 Windows 设备蓝屏循环重启——航空公司、医院、银行的柜台一排排黑掉。更新在 78 分钟内被撤回,但已经蓝屏的机器只能一台台进安全模式手动删文件。事后复盘里有一句关键的话:这类内容更新没有灰度。
Knight Capital,2012 年 8 月 1 日,星期三。 为了对接纽交所新的零售流动性计划,公司部署了一批新代码——这批代码重新激活了路由里一段 2005 年就被挪了位置、早已废弃的函数。开盘后的 45 分钟里,路由器往市场发了 4000 多万笔订单,只为成交 212 笔客户委托,亏掉超过 4.6 亿美元。最扎心的是 SEC 事后查明:当天开盘前,内部系统已经自动发出了 97 封 报错邮件,没人看。星期三,上午九点半,一切看起来都很正常。
把两件事放在一起看:一个输在「没有灰度」,一个输在「部署流程没人复核」——没有一个输在星期几。
四、真正的解咒:把「部署」和「发布」拆开
部署(deploy)是「把代码放上机器」,应该无聊、频繁、每天几十次;发布(release)是「让用户看到新功能」,应该可开关、可分组、可随时关掉。前者出问题最多回滚,后者出问题只需要关掉一个开关。
两件事粘在一起的时候,上面那些玄学就全回来了。
一个最小的开关实现,代码量比写一条上线公告还少:
type Flag = { key: string enabled: boolean // 总开关:出事了先关它,不用发版 rollout: number | string[] // 放量比例,或内测名单}
// FNV-1a:同一个用户永远落在同一个桶里,不会刷新一次变一次function hash(s: string): number { let h = 2166136261 for (const ch of s) h = Math.imul(h ^ ch.charCodeAt(0), 16777619) return h >>> 0}
function isOn(flag: Flag, userId: string): boolean { if (!flag.enabled) return false if (Array.isArray(flag.rollout)) return flag.rollout.includes(userId) return hash(userId + flag.key) % 100 < flag.rollout}有了它,17:30 上线就不再是赌博:先开 1%,盯五分钟指标,再开 10%、50%、100%。真出事,点一下开关,比 git revert + 重新构建 + 重新部署快一个数量级。
至于灰度、蓝绿、自动回滚、值班表,都是同一个思想的延伸:让每一次变更的影响范围小到可以承受,让每一次故障的处理动作小到可以随时执行。做到这两条,你就不需要「只读星期五」了——因为周三和周五没有区别。
五、周五上线自检清单
发版前问自己四句:
- 这次改动能一键回滚吗?回滚需要重新发版吗?
- 出事了谁会醒?他知道回滚命令在哪吗?
- 有没有开关能让它只对 1% 的用户生效?
- 如果 17:30 上线、18:00 炸了,18:01 谁在场?
最后一条答不上来的时候,你怕的其实不是星期五,是自己那套流程。
写在最后
段子继续讲,玄学继续拜——毕竟 sudo 前深呼吸不花钱。但心里要清楚:星期五只是一个变量名,事故的真正主题永远是「变更的影响范围」和「恢复所需的时间」。
所以下次有人在周五 17:20 问「这个能上吗」,最好的回答不是「不行」,而是:
能上。把开关关着推上去,周一再打开。
——这样星期五就赢了,而且是靠工程赢的。
参考来源
- Release Engineering — Google SRE Book:把发布做成「不需要工程师介入」的常规动作
- Accelerate: The Science of Lean Software and DevOps — Forsgren, Humble, Kim:部署频率与变更失败率的长期相关性
- CrowdStrike Channel File 291 事故说明 — ABC News
- CrowdStrike 故障导致 850 万台 Windows 设备崩溃 — The Verge
- SEC Charges Knight Capital With Violations of Market Access Rule(Release No. 34-70694)
延伸阅读:本博客里也有几篇讲「事故与人的距离」的文章——《历史上的著名 Bug》、《rm -rf 的悲惨故事》、以及昨天那篇《需求变更的经典笑话》(它有一节正好也在讲开关解耦)。