我花了3周把数据库备份从手动改成自动化的真实记录
上个月接了个制造业客户的运维改造活儿,他们核心业务库是MySQL 8.0,跑在阿里云ECS上,数据量大概2.5TB。最让我头疼的是,之前全靠DBA每天早上手动执行mysqldump,不仅容易忘,而且一旦备份文件损坏,恢复测试基本没法做。老板给我的deadline是两周内搞定全自动备份加灾备方案,还得保证恢复时间目标(RTO)控制在4小时以内。说实话,这压力不小,毕竟业务库一旦挂了,生产线就要停摆。
备份策略的取舍与优化
一开始我考虑过两种方案:一是继续用mysqldump逻辑备份,二是改用XtraBackup做物理备份。逻辑备份虽然通用性强,但对于2.5TB的数据量,mysqldump跑一次要4个多小时,而且CPU和IO占用极高,容易影响线上查询。试了一圈发现,XtraBackup的备份速度能快3-4倍,且基于InnoDB的崩溃一致性快照,对线上业务影响很小。所以我最终选了XtraBackup,配合crontab每天凌晨2点执行增量备份,每周日做全量备份。
配置其实不复杂,关键是要处理好参数继承。我在脚本里加了一段逻辑,先查找最近一次全量备份的位置,然后生成对应的增量备份参数文件。代码如下:
```bash
#!/bin/bash
LATEST_BACKUP_DIR=$(ls -t /backup/full/ | head -n 1)
xtrabackup --backup --user=backup_user --password=xxx --incremental --incremental-lsn=$LATEST_BACKUP_DIR
```
当时我觉得这样写就行,结果发现错了。XtraBackup的增量备份依赖全量备份的LSN(Log Sequence Number),如果直接取目录名去匹配,一旦目录结构变化或者备份失败重跑,LSN就对不上了,导致备份链断裂。后来我改成了在备份成功后,把LSN值存到一个独立的meta文件里,每次增量备份前先读取这个文件,这样容错性就高多了。
恢复流程的实战踩坑
备份只是第一步,真正的考验在于恢复。客户要求必须能验证备份是否真的可用,而不是“备份成功了”就算完事。我搭建了一个隔离的恢复测试环境,模拟全量+增量恢复的场景。这里有个坑死我的点:XtraBackup恢复前必须先执行prepare阶段,而增量备份的prepare需要链式依赖,即先prepare全量,再prepare第一个增量,以此类推。
我第一次测试恢复时,直接对最新的增量备份执行了prepare,结果报错说缺少前置LSN。排查了很久才发现,XtraBackup的prepare机制并不像某些工具那样自动识别依赖链,必须手动指定--incremental-dir并严格按顺序执行。为了自动化这个过程,我写了一个恢复脚本,自动解析备份目录树,生成正确的prepare命令序列。有意思的是,脚本还加入了一步:恢复完成后,自动启动一个临时的MySQL实例,执行SELECT COUNT(*)关键表校验,确认数据完整性。只有校验通过,才会在日志里标记“备份可恢复”。
有一次深夜演练,模拟主库宕机,我从备份恢复到临时实例,整个流程跑了1小时20分钟,比预期的4小时RTO目标快了很多。但问题出在应用连接池上,恢复后的库因为时区参数和原有主库不一致,导致部分定时任务报错。这个细节在纯数据库恢复测试里根本发现不了,必须结合应用层验证。后来我在恢复脚本里加了一步,自动比对并同步my.cnf的关键参数,这才彻底堵住漏洞。
现在这套方案跑稳了三个月,备份成功率99.9%,恢复演练每月一次,平均耗时控制在90分钟内。客户那边终于不用DBA半夜爬起来手动备份了。技术细节可以聊,但最核心的还是:备份的终极价值不在于“有没有备份”,而在于“能不能在灾难发生时真正救你”。
本文基于实际项目经验整理,欢迎在评论区交流技术问题。