先说结论:工作突发状况不是“意外”,是权限设计在报警
我不是专职 SRE,我是写业务代码的,前后被拉去救过 3 次火。最近一次是去年 11 月 17 日凌晨 2 点 13 分,企业微信电话把我吵醒:客户生产库 CPU 99.8%,RDS 是 MySQL 8.0.32,规格 db.r5.2xlarge,连接数 487/500,P99 从 180ms 拉到 8.4s。
我第一反应是慢查询,结果 SHOW PROCESSLIST 里有个账号在跑全量导出,pt-kill 还没配白名单,备份任务和报表任务撞在一起。
那一刻我意识到:突发状况不是“异常”,它是权限、调度、监控阈值一起被压力测试。
你平时给出去的每个权限、每个定时任务、每个“先临时开一下”的入口,都会在这种时候变成事故放大器。
第一步不是找根因,是 5 分钟内恢复可服务状态
很多教程让你先查日志、先定位代码,我不同意。
线上服务挂了,用户只关心能不能下单、能不能登录。
我的顺序是:1)拉群,指定一个指挥,一个记录,一个操作,避免三个人同时敲命令;2)看黄金指标:QPS、错误率、P99、连接数、CPU、内存、磁盘 IO;3)做最小可逆动作:限流、切只读、回滚、扩容、摘流量。
比如那次我先在 Nginx 加 limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;,把非核心接口限到 100r/s,然后 KILL 掉导出会话,再把报表账号临时禁用。
4 分 20 秒后 CPU 从 99.8% 降到 43%,P99 回到 620ms。
注意,这些动作必须可逆:限流能取消,只读能切回,回滚有版本号。
不可逆的删数据、改表结构、清缓存,除非万不得已,别在凌晨三点做。
对比:大厂 runbook 和小团队人肉救火,差的不是技术
我在上一家公司见过比较成熟的应急:PagerDuty 告警,5 分钟未 ack 自动升级到 leader,runbook 里写清楚每条命令、影响面、回滚步骤,事故群有机器人自动拉时间线。 小团队往往相反:告警发到钉钉群,没人认领;操作靠记忆,命令靠复制;事后复盘变成“甩锅大会”。 但大厂也不是万能,runbook 太厚没人看,权限太严导致止血慢。 我的独立观点是:别追求完美预案,先做“权限阈值表”。 比如:哪些账号能 kill 查询,哪些人能切只读,哪些人能回滚,超过 5 分钟找谁,超过 10 分钟要不要发公告。 把人和权限写清楚,比写 80 页预案有用。 我们后来把生产库账号分成 read_only、dml、ddl、kill 四类,报表账号只能 read_only,备份任务错开到凌晨 4 点 30 分,CPU 告警阈值从 85% 改成持续 2 分钟 90%。
可以直接照抄的 4 步应急模板
第 1 步,确认影响面:是全部用户还是部分?是登录、支付还是查询?
用 curl -o /dev/null -s -w '%{http_code} %{time_total} %{size_download}' 打 10 个核心接口,记录状态码和耗时。
第 2 步,止血:优先限流、降级、回滚、扩容。
K8s 用 kubectl rollout undo deploy/api -n prod,Nginx 用 return 503 摘掉问题节点,数据库用 pt-kill --busy-time=30 --match-command=Query --kill。
第 3 步,记录决策日志:时间、操作人、命令、结果、下一步。
别小看这个,事后复盘全靠它。
第 4 步,恢复后 48 小时内做复盘,只问三个问题:为什么没提前发现?为什么止血花了这么久?哪个权限/阈值/流程要改?
每个问题必须落到具体负责人和日期,比如“报表账号 read_only 改造,老周,11 月 20 日前”。
最后说点得罪人的:别把“突发状况”当成英雄时刻
我以前也觉得自己半夜爬起来救火很厉害,后来发现,能救火不代表系统健康。 真正该比的是 MTTR,平均恢复时间,不是谁加班多。 我们那次事故后统计:告警到 ack 用了 7 分钟,ack 到止血 4 分 20 秒,止血到恢复 18 分钟,总 MTTR 29 分钟。 后来把告警升级、权限表、报表错峰做完,第二次类似情况的 MTTR 降到 9 分钟。 你看,突发状况不会消失,但可以被压缩。 我的观点很直接:工作突发状况处理的核心,不是找根因,也不是写漂亮复盘,而是把“谁能在几分钟内做什么”提前定义清楚。 根因可以明天找,服务今晚得先活过来。