我干数据库这行快十年了,见过太多因为备份没做好而翻车的案例。上周还有个朋友找我哭诉,说公司数据库硬盘坏了,结果发现备份脚本跑了半年全是失败的,数据直接回到半年前。这种事儿每次听到都让我心里一紧,所以今天想把MySQL备份恢复这点事儿掰开揉碎了讲讲。

先说备份这事儿,很多人觉得不就是mysqldump一下嘛,还真不是那么简单。mysqldump是MySQL自带的逻辑备份工具,它把数据转换成SQL语句保存下来,好处是跨版本、跨平台都能用,坏处是数据量大了之后,恢复起来那个慢啊,一个10GB的库恢复可能要几个小时。我见过有人拿mysqldump备份几百GB的库,结果备份文件就占了好几个T的磁盘空间,恢复的时候更是等到花儿都谢了。
如果你数据量不大,比如几个GB以内,mysqldump完全够用。但要是上了几十GB甚至上百GB,就得考虑物理备份方案了。物理备份直接复制数据库的文件,速度快得多,恢复也快,但要求MySQL版本和操作系统基本一致。像Percona XtraBackup就是这方面的利器,它能在不锁表的情况下做在线备份,对生产环境影响很小。我推荐大家至少掌握这两种方案,小库用mysqldump,大库用XtraBackup,这样就能覆盖大部分场景了。
再说说备份策略,这里头学问大了去了。全量备份肯定要做,但每天都做全量备份,时间和空间成本都太高。所以业内通用的做法是:比如每周日做一次全量备份,周一到周六做增量备份,就是只备份从上次备份以来变化的数据。这样既能保证数据完整,又不会太浪费资源。不过增量备份有个坑,就是恢复的时候得按顺序把全量备份和所有增量备份都恢复了,中间任何一个备份文件损坏,后面的都白搭。相比之下,用binlog日志做增量备份会更灵活一些,因为binlog记录了所有数据库变更操作,你可以恢复到任意一个时间点,这个后面详细说。
binlog这东西,真的是MySQL里最容易被忽略但又最重要的功能之一。它是MySQL的二进制日志,记录了对数据库的所有修改操作。开启binlog很简单,在配置文件里加上log-bin=mysql-bin就行,但很多人压根没开,或者开了也不在意。实际上,binlog不仅能用来做增量备份,还能用来做数据恢复,比如你不小心删了一个表,或者执行了一条错误的UPDATE语句,只要有binlog,就能把数据恢复到出问题之前的状态。
举个例子,假设你上午10点误删了一张表,而你的全量备份是昨天凌晨做的,binlog从昨天凌晨到上午10点的记录都在。那么恢复流程就是:先恢复昨天的全量备份,然后重放binlog到上午10点之前,这样数据就完整回来了。这种恢复方式叫时间点恢复,是处理误操作最有效的手段。但前提是,你得提前开启binlog,并且保留足够多的binlog文件,不然一切免谈。
说完备份,重点说说恢复。恢复这事儿比备份难多了,因为备份是固定的流程,恢复却要面对各种突发状况。比如你恢复的时候发现备份文件损坏了,或者磁盘空间不够了,又或者恢复过程中MySQL版本对不上,这些情况我都遇到过。所以我的建议是,别等到出事了才研究恢复,平时就要定期做恢复演练,就像消防演习一样,真出事儿的时候才能不慌。
恢复演练具体怎么做?我建议至少每月做一次。找个测试环境,把最近的备份恢复一遍,看看数据是否完整,时间是否在可接受范围内。特别是那些用了增量备份和binlog的,更要多练几次,因为恢复步骤多,一步错步步错。我见过一个运维团队,平时备份做得挺好,但从来没演练过恢复,结果真出事的时候,花了整整两天才把数据恢复回来,公司业务都停摆了,损失惨重。
再补充一个很实用的技巧,就是备份文件的校验。很多人备份完就扔那儿不管了,也不检查备份文件是否完整。其实MySQL的mysqldump有个--single-transaction参数,能在备份时保证数据一致性,但这也意味着备份过程中如果有写入操作,可能就会不一致。所以备份完成后,最好用mysqlcheck或者直接恢复到一个临时库来验证一下。这个过程虽然多花点时间,但能让你在真正需要恢复的时候,确保备份是能用的。
说说备份文件的存储。我强烈建议,备份文件别只存在本地磁盘上,因为如果服务器硬件坏了,或者中病毒了,本地备份也跟着完蛋。一定要做异地存储,比如传到云存储上,或者至少放到另一台机器上。另外,备份文件的保留策略也很有讲究,比如保留最近7天的每日备份,保留最近4周的每周备份,保留最近12个月的每月备份。这样既能满足短期恢复需求,又能应对长期数据保留的要求。
说到底,MySQL备份和恢复这事儿,说难也不难,说简单也不简单。核心就是多实践、多演练,把备份当成一项日常运维工作来对待,而不是等到出了事才想起来。我记得有个老前辈跟我说过一句话,备份就是保险,平时用不上最好,但真用上的时候,能救命。这话糙理不糙。


