1. 前言:第一次参与线上事故的全流程
今天是坚持写博客的第四天。回忆起刚入职一年的时候,线上的一次重大故障让我至今记忆犹新——MySQL CPU飙升至100%,导致整个生产库相关业务全线崩溃,持续了近一个小时。这次事故不是我写的代码引起的,而是我作为排查小组成员,全程参与了定位和修复。今天就来详细复盘一下这次事故的全过程,包括排查思路、问题分析和最终的解决方案。
2. 事故经过:慢查询引发的“多米诺骨牌”
2.1 故障初现
那天早上8:40,部分客户陆续开始上班。我们的定时任务每2分钟执行一次,负责处理活跃设备的数据。此时MySQL内存占用从25%缓慢上升到35%。随着高峰期到来,参与活动的设备越来越多,定时任务压力也随之增大。
告警服务开始不断预警,但我们那会儿还没正式上班,没人第一时间注意到。
2.2 故障爆发
到了9:17,灾难终于爆发:生产环境所有依赖该MySQL实例的业务全部宕机报错。
这时候大家才意识到问题的严重性,所有人都开始紧急排查。
3. 排查过程:抽丝剥茧找元凶
3.1 初步怀疑
面对突然崩溃,我们最初怀疑有以下几种可能:
- 接口被暴露,被DDOS攻击?
- 某个定时任务异常?
- 某段代码出现死循环或频繁查库?
首先,我们排查了网关日志,没有发现某个服务被异常高频请求,基本排除了DDOS攻击的可能。
3.2 深入分析
既然不是外部攻击,那极有可能是内部服务自身引发的。我们逐一排查了各个服务的运行状态和日志,最后将目光锁定在一个定时任务上。
- 这个定时任务在测试环境下表现一直正常,但上线后却导致了事故。
- 为了彻底搞清楚原因,我特意翻看了同事之前的git提交记录,仔细review了相关代码,终于发现了关键问题!
4. 技术细节:SQL优化与最左匹配原则
4.1 问题源头
- 同事在定时任务中做了较大改动:
- 新增了一个复杂的大事务
- 联表查询时用“大表驱动小表”
- 修改了原有索引,但没有遵循最左匹配原则
最左匹配原则:
假设有联合索引(A, B, C),查询条件必须从A开始连续,否则索引失效。例如:
- 查询(A, B)能走索引
- 查询(B, C)不能走索引(因为没有A)
同事修改后的SQL语句恰好违反了这个原则,导致查询无法利用索引,变成了全表扫描。
4.2 问题定位
由于大表全表扫描,大事务堆积,数据库连接数被迅速耗尽,CPU飙升至100%,最终拖垮了整个MySQL实例,所有相关业务挂掉。
5. 补救措施与优化
5.1 紧急止损
问题定位后,我们第一时间停掉了有问题的定时任务。
随着任务停止,MySQL内存和CPU占用逐渐下降,9:55左右恢复到正常水平,所有业务线陆续恢复。
5.2 持续优化
- 大事务拆分成小事务:减少单次操作对数据库的压力。
- SQL优化:改用“小表驱动大表”,最大限度利用内存和索引。
- 新增符合业务场景的索引:确保所有关键查询都能命中索引。
- 临时上线修订版本:当天晚上就进行了升级修复。
- 次日持续监控:第二天一早紧盯MySQL资源使用情况,确认问题未再复现。
6. 经验总结 & 成长感悟
这是我第一次全程参与如此严重的线上事故。从接到市场反馈,到团队协作定位问题,再到最后修复上线,每一步都让我收获良多:
- SQL优化和索引设计的重要性:任何一个小失误都可能导致灾难性后果。
- 生产环境和测试环境差异不可忽视:流量、数据量、并发量完全不同,要有敬畏之心。
683

被折叠的 条评论
为什么被折叠?



