上周五晚上十一点,我正刷剧,手机突然震个不停。运维群里炸了锅——线上 MySQL 数据库挂了,所有业务全部瘫痪。我赶紧打开电脑连上 VPN,心跳直接飙到 120。做过运维的都懂,数据库崩溃不是闹着玩的,用户数据、订单记录、交易流水全压在那几台机器上。最要命的是,你根本不知道问题出在哪,是硬件故障、配置错误,还是哪个程序员手滑跑了慢查询。那一刻,时间像被按了暂停键,但脑子里已经开始飞速转:备份在不在?binlog 还完整吗?恢复窗口有多大?

数据库崩溃的原因五花八门,但最常见的就几种。硬件层面,磁盘坏了、内存条出问题、电源炸了,这些物理故障最直接,也最让人头疼。软件层面,MySQL 本身有 bug、操作系统内核不稳、文件系统损坏,都能让你措手不及。还有人为因素——有人误执行了 DROP TABLE,或者某个连接池配置不当把数据库压垮了。最隐蔽的是慢查询积累,平时跑个几秒没事,等数据量大了,一条查询就会堵死整个库。上周我们遇到的就是这种情况:一个开发同事上线了新功能,没加索引,全表扫描直接把 CPU 拉到 100%,连接数爆满,数据库直接 hang 住了。
遇到这种紧急情况,第一步不是动手修,而是先冷静判断。要弄清楚服务不可用是 MySQL 进程挂了,还是操作系统还在但连不上,亦或是网络层面的问题。我们那次先执行 ,直接报错 “Can't connect to local MySQL server through socket”。这说明 MySQL 进程已经崩溃,不是网络问题。随后查看系统日志,。日志里密密麻麻的报错信息,但最显眼的是 “InnoDB: Corruption in the InnoDB tablespace” 和与 “ibdata1” 相关的提示。完了,InnoDB 数据文件损坏,这是最严重的故障之一。心跳直接飙到 140。
确认是 InnoDB 表空间损坏后,接下来要评估恢复策略。第一想到的是备份还原,这是最稳妥的方案。但问题来了——上次全量备份是三天前,增量备份只做了每天一次。如果直接还原,会丢失最近三天的数据。业务那边肯定不干,老板更不干。只能尝试 binlog 恢复,把备份还原后的数据用 binlog 重放三天内的所有修改。但前提是 binlog 文件完好无损。我们检查 binlog 目录,发现文件都在,却有一个文件大小异常,只有正常的一半。这说明 MySQL 崩溃时,那个 binlog 没写完,里面的数据不完整,情况更麻烦。
这时只能依赖 InnoDB 自身的崩溃恢复机制。MySQL 启动时,InnoDB 会自动检查 redo log,把已提交但未写入数据文件的事务重做,把未提交的事务回滚。这个机制叫 “Crash Recovery”,理论上能修复大部分问题。但前提是 redo log 本身没有损坏。我们尝试重启 MySQL,结果启动到一半又挂了,日志显示 “InnoDB: Database page corruption on disk or a failed file read”。这说明自动恢复失败,需要手动介入。于是只能尝试 参数,从 1 到 6 逐级提升,强迫 InnoDB 跳过错误检查,尽量把数据读出来。
启动失败,改成 2 仍不行。到 3 的时候 MySQL 终于起来了,但只能读不能写。我们赶紧用 把能导出的表全部导出来。这个过程特别煎熬,因为有些表的数据可能不完整,导出时会报错跳过。每跳过一个错误,心里就咯噔一下。最终导出了 80% 的表,剩下的 20% 要么完全损坏,要么无法读取。此时只能做取舍——是继续尝试更高级别的恢复,冒着数据进一步损坏的风险,还是接受现状,用这 80% 的数据重建业务。
我们选择了后者。先把导出的数据导入到一台新机器上,然后从备份里找那些损坏表的历史数据。接着用 binlog 工具(如 )把未损坏的 binlog 文件重放,尽量补充最近三天的数据。但那个不完整的 binlog 只能恢复到一个小时前,这意味着有一个小时的业务数据彻底丢失。恰好那个小时是晚高峰,订单量最大。业务部门在群里炸了锅,称损失至少几十万。我们也只能接受,数据库恢复往往没有完美方案,只能两害相权取其轻。
事后复盘,这次事故暴露了三个问题。第一,备份策略不够完善,全量备份间隔太长,增量备份频率太低。第二,慢查询监控不到位,那个慢查询跑了整整一天才被发现。第三,权限管理太松,开发直接连线上库执行 DDL 操作。我们连夜改进备份策略,改为每两小时一次增量备份、每六小时一次全量备份。加了慢查询阈值报警,任何超过 1 秒的查询都发短信通知。还收回了线上库的写权限,开发只能通过审核过的脚本操作。这些措施看起来很基础,但很多公司懒得做,等出了事才后悔。
数据库崩溃恢复说到底是在和时间赛跑。你永远不知道下一个崩溃何时来,但可以提前做好准备。备份要可靠,监控要到位,权限要收紧,应急预案要演练。更重要的是,团队里必须有几位真正懂 MySQL 底层原理的人,了解 redo log、undo log、binlog 的工作机制,才能在事故发生时快速决策。事故后,我们每季度做一次数据库恢复演练,模拟硬件损坏、误操作等各种故障场景。虽然平时觉得浪费时间,但真到出事那天,你会发现这些演练能救命。毕竟,数据库崩了不可怕,可怕的是不知道怎么把它救回来。


