凌晨三点,电话铃声炸响。那头是运维同事沙哑的声音:“数据库挂了,主库和从库全都起不来。”你从床上弹起来,脑子里只有一个念头:数据还在不在?这是每个做技术的都怕遇到的场景,但真遇上了,慌没用。数据库崩溃这事儿,跟人得急病一样,能不能救回来,取决于两件事——平时有没有做好“体检”和“备份”,以及事发时有没有一套清晰的抢救流程。这篇就把这套流程从头到尾捋一遍,你照着做,至少能让自己少踩几个坑。

先把最要紧的说了:数据恢复的第一原则,是“停止一切写操作”。数据库崩了,你手痒痒想重启试试?先忍住。想跑个脚本修复一下?也先停手。这时候任何一次写入,哪怕是写一条日志,都可能覆盖掉还没损坏的数据块。正确的姿势是立刻把数据目录整个冻结起来,用文件系统快照或者直接复制一份出来,作为只读的“证据副本”。后续所有操作都在副本上进行,原始目录碰都不碰。这一步做好了,哪怕后面操作失误,你还有后悔药吃。
接下来要判断崩溃的类型。是硬件层面的磁盘坏道,还是软件层面的数据文件损坏?是误操作删了表,还是主从复制出了岔子?不同类型的崩溃,恢复手段天差地别。有个土办法很实用——看错误日志。MySQL的error log、PostgreSQL的pglog,还有系统日志dmesg,通常都会留下线索。比如“InnoDB: Database page corruption on disk”这类信息,基本就能断定是数据页损坏。如果是“Out of memory”导致的进程被杀,那大概率是配置问题,数据文件本身没坏,重启可能就完事了。判断清楚再动手,能省下大把时间。
如果是数据文件损坏,最常用的武器是数据库自带的恢复工具。MySQL有innodbforcerecovery参数,从1到6,数字越大代表越暴力地跳过损坏检查。注意,这个参数是“能不进则不进”的,因为级别越高,数据丢失的风险越大。正确做法是从1开始试,每次启动后赶紧用mysqldump导出数据,导出成功就收手。PostgreSQL那边则可以用pgresetwal来重置预写日志,但这是个危险操作,非到万不得已别用,因为它会丢弃最近的事务记录。记住一个原则:工具能修就修,修完立刻备份,别在修复后的库上直接跑业务。
备份,永远是数据恢复的底牌。但备份也分三六九等。物理备份(比如XtraBackup做的全量备份)能恢复到备份时刻的完整状态,配合binlog或WAL日志,可以追到崩溃前的一秒。逻辑备份(mysqldump导出的SQL文件)恢复慢,但胜在灵活,误删单表时特别好用。最怕的是那种“备份了但没验证过”的情况——真到恢复时发现备份文件是坏的,那才叫欲哭无泪。所以平时一定要定期做恢复演练,别嫌麻烦,真到关键时刻,演练过的人跟没演练过的人,完全是两种状态。
如果备份也不完整,或者备份时间点离崩溃时刻太远,那就得考虑“找补”了。binlog是MySQL的救命稻草,只要binlog还在,从备份点重放到崩溃前,数据基本能追平。PostgreSQL则靠WAL归档。但这里有个坑:很多团队为了省磁盘空间,binlog只保留三天。你崩溃的时候如果备份是五天前的,中间那两天的binlog早就清了,那就真没辙了。所以,binlog保留周期一定要大于备份周期,而且最好异地存一份。另外,如果只是误删了某张表,用binlog做时间点恢复比全量恢复要快得多,成本也低得多。
再说一个容易被忽视的点:恢复过程中的“数据一致性”问题。你从备份恢复了一个库,数据能查了,但业务真的能跑吗?跨表的外键、自增ID的冲突、缓存和数据库的不一致……这些“软问题”往往比硬故障更折磨人。有个实际案例,某公司恢复完数据库后,订单表正常,但用户表里的余额和交易流水对不上,只能手动调账,折腾了两天。所以恢复完成后,一定要跑一遍完整的业务校验脚本,重点检查关联表、统计数据和关键业务指标。别急着对外宣称“恢复了”,先让业务方验证一下再说。
得说说人。数据恢复这事儿,七分靠流程,三分靠心态。我见过太多人,一看到数据库崩了,手忙脚乱地各种命令一顿敲,结果把能恢复的数据也给搞坏了。冷静下来,按步骤走,哪怕慢一点,也比瞎折腾强。还有,事后复盘比恢复本身更重要——崩溃原因是什么?监控告警为什么没提前发现?备份策略哪里不合理?把这些写进文档,下次就不会再踩同一个坑。数据恢复的最高境界,是你永远用不上这篇指南,但真用上时,你能从容不迫地把它变成一篇文章里的“成功案例”。
数据库崩溃不吓人,吓人的是没准备。备份做扎实,流程记清楚,心态放平稳,就算真遇到最坏的情况,你也能从废墟里把数据一点一点挖回来。记住,数据是死的,人是活的——只要方法对,总能找到出路。


