工作失误了怎么办?我删过18427行生产数据,对比Knight Capital亏4.4亿和GitLab删库直播后,总结了一套前30分钟止损流程

🔑 关键词:工作失误,生产事故复盘,止损流程,COE复盘文档,删库

📖 摘要:从一次凌晨误操作全表更新18427行SKU数据的亲身经历出发,对比Knight Capital 45分钟亏4.4亿美元、GitLab删库后YouTube直播恢复、英国邮局Horizon案三个真实案例,拆解工作失误真正的分水岭在哪里,并给出一套可以照着做的前30分钟止损步骤和复盘文档写法。

凌晨1点47分。

图片

我盯着屏幕上那行 UPDATE sku SET is_active = 0 —— 没有 WHERE。

MySQL 返回:Query OK, 18427 rows affected。

一万八千四百二十七个商品,全下架了。我们的 APP 首页在接下来 11 分钟里是空的,购物车点进去就是「该商品已下架」。

我做了三件事:一、Ctrl+C 停掉后面排队的脚本;二、在运维群里打「是我,sku 表全表更新了,正在回滚」;三、打开 binlog 定位那条 SQL 的时间戳。

事后老板问了我一句:你知道你差一点就把公司两周的 GMV 打没了吗。

我说知道。但其实那 11 分钟里我脑子里只有一件事——我有没有备份。

后来我花了很多年琢磨「工作失误」这件事,发现大多数人(包括当年的我)对失误的理解都是错的。我们以为失误的严重程度取决于损失金额。不是。它取决于两件事:可逆性,和你在前 30 分钟做了什么。


2012 年 8 月 1 日,美东时间 9:30,纽交所开盘。

图片

Knight Capital 的 SMARS 系统开始往市场里灌订单。45 分钟后,他们亏了 4.4 亿美元。当天公司市值蒸发超过 75%,四个月后被 GETCO 收购。

技术原因听起来蠢到不可思议:新代码要部署到 8 台服务器上,工程师手动部署了 7 台,第 8 台漏了。那台服务器上跑的是旧代码,里面有个 2003 年就废弃的功能叫 Power Peg——它会把订单疯狂地发出去。

这里有个关键细节:Power Peg 早就被「停用」了,代码却没删。新代码里有个复用的标志位,在新代码里它是个普通参数,在旧代码里它是 Power Peg 的开关。8 台里 7 台是新代码,这个 flag 被赋值也没事;唯一那台旧代码,一收到 flag 就启动了。

如果有个自动化部署校验——比如拉 8 台机器的代码版本哈希对比——这事不会发生。如果有「一键停止交易」的开关,损失可能停在 2000 万而不是 4.4 亿。

对比一下 GitLab。

2017 年 1 月 31 日,一个工程师做数据库维护。他以为自己在 db2 上操作,实际终端连的是 db1——主库。他敲了 rm -rf /var/opt/gitlab/postgresql/data。

300GB 数据,开始删。

GitLab 当时有 5 种备份机制:pg_dump、LVM 快照、Azure 磁盘快照、S3 上传、一个复制的从库。事后查明,5 个里 4 个失效——pg_dump 因为 PostgreSQL 版本不匹配一直报错没人管;LVM 快照因为程序改了数据目录路径而快照了空目录;Azure 快照功能没开;S3 上传因为磁盘满了中断。

图片

他们最后靠一个 6 小时前的 LVM 快照恢复,丢了 6 小时的数据,涉及数千个项目的 issue、merge request 和评论。整个恢复过程在 YouTube 上直播,几万人看。

9 天后,GitLab 把完整复盘文档放到了网上,包括那个工程师敲的命令、时间戳,以及「我们为什么没早发现备份是坏的」。


这两个案例放在一起,对比度就出来了。

Knight Capital 死在一个没删的旧功能和一个没校验的部署流程上。GitLab 活下来,不是因为失误小,而是因为失误发生后的 6 小时里,每一步都做对了:立刻公开、立刻止损、立刻查备份、恢复完立刻写文档。

但还有第三个案例,比前两个都黑。

英国邮局 Horizon 案。从 1999 年到 2015 年,富士通给英国邮局做的 Horizon 系统在账目上不断出现「亏空」。邮局的处理方式是:认定是支局长偷钱。超过 700 人被起诉,有人坐牢,有人自杀,有人家庭破裂。

2019 年高等法院判决:Horizon 系统存在缺陷,「亏空」是软件 bug 造成的。2024 年英国政府立法为受害者平反。

这个案子里,失误本身——软件 bug——造成的损失可能是几百万英镑。但组织为了掩盖失误、坚持「系统不会错」造成的代价,是几百个人的人生。

图片

所以我现在有一个很固执的观点:工作失误的破坏力,90% 不来自失误本身,来自组织(和你自己)对失误的反应方式。一个能公开删库直播的公司,比一个死不认错的公司安全一百倍。


那具体怎么做。我自己踩过坑之后,总结了几个能照着操作的东西。

失误发生后的前 30 分钟,按这个顺序走:

0 到 3 分钟:停手。不要「先修修看」。我见过太多把一次数据错乱变成两次的人——第一次是误操作,第二次是慌乱中的补救。先 Ctrl+C,先关掉脚本,先把鼠标放下。

3 到 8 分钟:判断可逆性。问自己三个问题:这是不是写操作(删/改)?有没有备份?备份的时间点是多久之前?如果是读操作或者只是查询错,你基本没事。如果是写操作且没备份——接下来每一分钟都是钱。

8 到 15 分钟:通知。用这个句式:「我在 X 点 X 分对 Y 系统执行了 Z 操作,影响范围是 A,目前状态是 B,我需要 C。」不要写「我不小心」「我可能」「好像」。我当年发的第一条消息就是「是我,sku 表全表更新了,正在回滚」——12 个字,够了。

15 到 30 分钟:记录时间线。用统一的时区,建议 UTC,或者全公司约定一个。写下:你做了什么、系统反馈是什么、你观察到什么、你又做了什么。别凭记忆,翻终端历史、翻 binlog、翻监控面板。Knight Capital 的复盘精确到毫秒,就是因为日志完整。

图片

30 分钟后:开始修。但修之前先定一个人负责对外沟通,别让所有人都在群里问「好了吗」。

日常要提前准备的三件事:

第一,止损开关。Knight Capital 如果有「一键停交易」,4.4 亿能变成 2000 万。你们的系统有没有一个能立刻断掉写操作的按钮?没有的话,这就是你今年最该做的事,优先级高于任何新功能。

第二,备份验证。GitLab 的 5 个备份坏了 4 个。备份不是「配置了」就行,是「恢复过」才算。每季度做一次真实恢复演练,把恢复出来的数据跟生产对比行数。具体一点:抽 20 张表,行数误差超过 0.1% 就要查。

第三,部署校验。8 台机器手动部署,漏 1 台的概率不低。加一步自动校验:部署完自动拉每台机器的代码版本哈希,不一致就报警,并且阻止流量接入。

复盘文档怎么写:

亚马逊的 COE(Correction of Errors)有个规则我觉得很对:文档里禁止写「因为某某某疏忽」。只能写「因为某系统缺少某校验」。

这不是为了免责,是为了让文档有用。你写「张三手滑删了库」,下周换个张三还会删。你写「生产环境对 rm -rf 没有二次确认,且主从库地址在终端提示里不可区分」,下周就能加上确认弹窗和终端颜色区分。

我现在的复盘模板就 5 个部分,一页纸:时间线、影响范围、根因(到系统层面为止)、已做的止损、待做的改进(每条必须有负责人和日期)。

图片


最后说个事。

我那次 sku 全表更新的 11 分钟里,公司损失大概是七万多的 GMV——因为当时是凌晨,流量低。

如果我是在晚上 8 点干的呢?可能是一百多万。

如果我再晚发现 5 分钟呢?binlog 回滚的时间窗口就过了。

这些「如果」现在想起来还是后背发凉。但也正是这些如果,让我后来做任何写操作前都会先跑一遍 SELECT COUNT(*) 看看影响行数——这个习惯,是我用 18427 行换来的。

工作失误这个东西,没人能避免。Knight Capital 的工程师、GitLab 的运维、英国的邮局局长,没人是故意搞砸的。

区别只在于:失误之后那 30 分钟,你是忙着掩饰,还是忙着止损。

🏷️ 标签: