上周四晚上十一点,我正在改稿子,突然手机炸了。运维群里连刷十几条“数据库挂了”,紧接着产品经理的电话就追了过来,声音里带着熟悉的恐慌——订单系统打不开了,用户在前台报错,后台管理页面全是白屏。我问他什么情况,他说不知道,只知道 MySQL 连不上了。我让他先看错误日志,他沉默了两秒,才问日志在哪看。这就是很多公司的现状:数据库崩了,第一个慌的不是 DBA,而是连 MySQL 错误日志路径都不清楚的业务方。

MySQL 崩溃其实有多种情况,最常见的三类是:磁盘满、内存耗尽、InnoDB 损坏。你要做的第一件事不是想着怎么恢复数据,而是先弄清楚它到底为什么挂了。最简单的办法是查看错误日志,默认路径在 /var/log/mysqld.log,或者用 查询。打开日志,搜索关键词 “error” 或 “crash”,往往能直接定位根本原因。我见过最离谱的一次,崩溃原因是 /tmp 目录被写满,MySQL 写不了临时表,直接挂了。运维查了三个小时也没发现,是我看了一眼日志才找到线索。
如果连 MySQL 都启动不了,那就麻烦了。这时候先别慌着跑数据恢复工具,先尝试能否进入安全模式。MySQL 有一个参数 ,启动时加上它可以绕过权限检查进入数据库。进去后别急着改数据,先看看表的状态。用 检查可疑的表,如果显示为 “crashed” 或 “in use”,大概率是表结构损坏。这时可以尝试 修复,但要注意,这个命令只在 MyISAM 引擎下有效,InnoDB 则别指望了。
InnoDB 崩了才是真正让人头大的事。InnoDB 支持事务和崩溃恢复,理论上它有 redo log 和 undo log,启动时会自动回滚未完成的事务。但有时候数据文件损坏得太严重,MySQL 启动到一半就报错退出,连恢复过程都跑不完。这时可以尝试几个“骚操作”:在配置文件里加一行 ,让 MySQL 启动时跳过部分检查。该参数可取 1~6,数值越大跳过的检查越多,但也越容易丢数据。一般从 1 开始试,能启动就赶紧把数据导出来,然后重建表。
有个朋友曾吐槽,他公司 MySQL 崩了,他直接把 调到 6,虽然启动成功,但进去一看,整张表的数据全变成乱码。这就是暴力恢复的代价。所以如果不确定问题出在哪,最好从最低级别开始尝试。还有个小技巧:在这种模式下,MySQL 会禁止写入,只能用 查询数据,查询到后用 导出。导出成功后,删掉损坏的表,重新建一个干净的库,再把数据导回去。
如果连 都救不了,那就只能考虑第三方工具了。Percona Data Recovery Tool for InnoDB 在圈子里口碑不错,能直接从 InnoDB 数据文件里把行记录扒出来。但使用它需要一定的技术基础,你必须清楚表结构、字段类型和索引信息,否则扒出来的数据可能对不上号。我见过有人用它恢复了一张表,却发现 ID 字段全乱了,只能手写 SQL 一条条修正。该工具更适合应急,不建议作为常规手段。
还有一种极端情况:连数据文件都坏了,比如 ibdata1 损坏或被误删。这时很多人第一反应是跑二进制日志(binlog)。如果你开启了 binlog,且日志文件完整,恭喜你,还有救。可以从最近一次完整备份开始,然后回放 binlog 到崩溃前的一秒。但这里有个坑:binlog 默认是按时间顺序存的,如果不知道崩溃的确切时间点,回放时可能把错误操作也一起回放,导致二次损坏。因此回放前,最好用 把日志解析成文本,先检查哪些语句有问题,再手动跳过。
我认识一个做电商后端的朋友,他们公司曾因一次手抖执行了 ,整个订单表瞬间消失。他们既没开 binlog,也没有当天备份,只能从前一天凌晨的全量备份恢复,结果丢失了一整天的数据。老板气得当场拍桌子,但能怎么办?没有 binlog,DBA 也束手无策。所以每次有人问我数据库崩了怎么恢复,我都会反问一句:平时有做备份吗?开 binlog 了吗?如果两样都没有,崩了就是崩了,神仙也救不了。
说到底,数据库恢复这件事,80% 的功夫在平时。崩溃时你可以疯狂百度、翻各种教程、试各种参数,但真正决定能否把数据救回来的,是你之前是否做好了备份、是否开启了 binlog、是否记录了表结构。我见过太多公司,平时舍不得花钱买备份服务器,舍不得花时间配置 binlog,结果数据库一崩,损失几十万才后悔。所以看完这篇文章,你最好现在就去做三件事:检查 binlog 是否开启、确认备份策略是否覆盖全库、把错误日志路径截图保存到手机。万一哪天崩了,至少不会连日志在哪看都不知道。


