半夜两点,手机突然震个不停。监控系统报警:数据库挂了。你爬起来打开终端,发现昨天误删了一张核心表,而最近的备份,还是上周的。那种感觉,就像把整年的工资放在钱包里,然后钱包丢了。MySQL作为最流行的开源数据库,扛着无数公司的核心业务,但很多人对备份的态度,跟对待保险一样——买的时候嫌贵,出事的时候才后悔没多买点。

备份这件事,最反直觉的地方在于:你花80%的精力去搞高可用、读写分离、集群部署,以为万事大吉了,结果一条就把所有努力清零。高可用解决的是硬件故障、网络抖动,但解决不了人为失误。而人为失误,恰恰是数据丢失的头号原因。所以备份不是高可用的补充,它本身就是一道防线,甚至是最重要的一道防线。
先搞清楚备份的三种基本姿势。第一种是逻辑备份,它把数据导出成SQL语句,好处是跨版本、跨平台都能恢复,还能单独恢复某张表,坏处是数据量大时慢得让人抓狂。第二种是物理备份,直接拷贝数据文件,比如用,速度快,但要求MySQL版本和操作系统尽量一致,否则恢复时可能翻车。第三种是二进制日志,也就是binlog,它不备份全量数据,而是记录所有变更操作,用来做增量恢复和时间点恢复。
我见过太多人只会用一把梭,不管数据量多大,每天凌晨全量导出一次。等数据到了几十个G,备份要跑两三个小时,业务高峰期的性能被拖垮,然后就开始抱怨备份太慢。实际上,对于大库,你应该用物理备份做全量,用binlog做增量,再配合定时任务,把备份频率从一天一次压缩到一小时甚至几分钟一次。这样即使出问题,最多损失几分钟的数据,而不是一整天。
备份策略的制定,核心就两个词:RPO和RTO。RPO是你最多能容忍丢多少数据,RTO是你最多能容忍停机多久。如果你说“数据丢了半小时也能接受”,那RPO就是30分钟,备份频率就可以放宽到20分钟一次。如果你说“数据库挂了必须10分钟内恢复”,那RTO就是10分钟,你得提前演练恢复流程,而不是临时翻文档。这两个指标不量化,备份策略就是拍脑袋。
讲个真实案例。我一个朋友的公司,数据库每天凌晨2点用做全量备份,备份文件存到另一台服务器上。一切看起来都挺正常,直到有一天早上,开发误操作删了一张订单表。运维赶紧去拉备份,结果发现备份文件是坏的——因为磁盘满了,备份写到一半就中断了,但脚本没检查退出码,以为成功了。只能靠binlog从昨天凌晨2点重放到删除那一刻,好在binlog还完整,折腾了四个小时才恢复。从那以后,他们的备份脚本里多了三行:检查退出码、校验备份文件大小、随机抽表做恢复测试。
这个案例说明两件事。第一,备份不是“执行了”就完事,必须验证备份文件的有效性。第二,恢复流程必须演练过,否则真出事的时候,你连binlog怎么回放都记不住。我建议每个季度做一次完整的恢复演练,模拟“数据库彻底损坏,从零开始恢复”的场景,把每一步都记录下来,形成操作手册。别嫌麻烦,真出事的时候,这套手册能救你的命。
再说说binlog的使用。全量备份只能恢复到备份时刻的状态,之后的变更都在binlog里。恢复的思路是:先恢复最近一次全量备份,再用回放从备份时刻到故障时刻的binlog。回放的时候有个坑——如果你误删了表,直接回放全部binlog,会把那条也执行一遍。正确做法是先用定位到删除语句之前的位置,或者用和指定时间窗口,把删除操作排除掉。
还有一个容易被忽略的点:binlog本身也可能丢失。如果你的binlog和数据文件在同一个磁盘上,磁盘坏了,两个都没了。所以binlog最好单独存放,或者定期同步到远程。另外,binlog的保留时间也很讲究。保留太短,出问题时没有足够的增量日志;保留太长,磁盘吃紧。我一般建议至少保留7天,具体根据你的数据变更频率来定。
说说备份文件的存储。很多人把备份放在数据库服务器本机,省事,但风险很大——服务器宕机、磁盘损坏、机房火灾,备份跟着一起没了。正确的姿势是“异地多副本”:至少一份在本地(方便快速恢复),一份在异地的对象存储或者另一台机器上。现在云厂商的对象存储都很便宜,把备份传上去的成本很低,但关键时刻能救命。别省这个钱。
数据安全这件事,从来不是靠运气。备份策略、验证机制、恢复演练,每一环都得落实。MySQL备份和恢复的实战,说白了就是三个问题:备份够不够全、恢复够不够快、演练够不够勤。把这三个问题回答好了,数据库再出状况,你也能从容应对。毕竟,半夜爬起来恢复数据,谁都。


