2024年3月15日,周五,晚上8点47分。我正蹲在马桶上刷手机,突然钉钉炸了。监控群连发12条告警:ecs-prod-01 CPU使用率98%,负载15.2,MySQL活跃连接数387。我裤子都没提好就冲到电脑前。这不是演习。我们是个小电商团队,日订单量大概2万单,服务器就一台4核8G的阿里云ECS,MySQL 5.7,PHP 7.2。平时CPU在30%左右晃荡。当时第一反应:完了,是不是被打了?但查了流量,正常,没有DDoS。那就是内部问题。
打开Grafana,看到CPU从8点40分开始爬坡,8点45分直接拉满。top命令,mysqld占300%多。show processlist,看到一个SQL:SELECT * FROM orders WHERE create_time > '2023-01-01',状态是Sending data,已经跑了4分12秒。orders表有260万行,create_time没索引。谁干的?问了一圈,运营小张说他在导数据,用Navicat直接连的生产库。我他妈当时真想骂人。但来不及,先kill掉,进程ID 12345。kill之后,CPU降到45%,但连接数还是高。因为还有几个类似的查询排队。又kill了3个。然后临时加索引:CREATE INDEX idx_create_time ON orders(create_time); 耗时12秒。CPU回到28%。服务恢复。总共47分钟。这47分钟里,我手抖了3次,打错两次命令。
我以前在某个中厂干过,那边有SRE团队,有完善的告警、预案、值班表。但小公司呢?你就是SRE。这里有个全新观点:工作突发状况的解决质量,不取决于你的技术多牛,而取决于你平时攒了多少“人情冗余”和“工具冗余”。人情冗余是:你平时帮过谁,谁愿意在你半夜求救时回你消息。我当时给一个前同事发微信,他秒回,远程帮我看了下慢查询日志。工具冗余是:我电脑里有个文件夹叫“救火”,里面存了20个常用脚本,比如一键杀慢查询、一键看连接数、一键备份。这次用到了三个。还有,老板当时回我:“别慌,先恢复,责任我来担。”这句话比任何技术都管用。
如果你也遇到类似情况,别学教科书,学我。第一步,确认影响面:curl -I 你的域名,看返回码;看监控,CPU、内存、连接数、QPS。第二步,快速止血:如果是数据库,show processlist; 找到耗时超过60秒的,kill掉;如果是应用,重启大法,但先记录PID。第三步,定位根因:看慢查询日志,一般路径 /var/log/mysql/slow.log,用mysqldumpslow -s t -t 10 slow.log 看前10条。第四步,修复:加索引,加缓存,加限流。比如我们后来加了Redis缓存,把订单查询QPS从800降到200。第五步,复盘:写文档,但别写“加强监控”这种废话,写“谁在什么时间做了什么,导致什么,下次怎么拦”。我们后来给Navicat加了只读账号,生产库禁止直接导出超过1万行。
这事之后,我得了“告警PTSD”,手机一响就心跳加速。但我也明白了一件事:工作突发状况不是用来“战胜”的,是用来“共存”的。你永远会有突发状况。区别在于,你是一个人扛,还是一群人扛。我现在每周五下午都会花20分钟检查一遍“救火包”:脚本还能跑吗?联系方式更新了吗?备份最近恢复过吗?这些小事,比任何应急预案都实在。最后说一句:别信那些“从容应对”的鸡汤,真实情况是,你一边骂娘一边敲命令,最后恢复了,然后去厕所把没提好的裤子提好。