恢复实战演练:全量恢复流程、基于时间点的恢复(PITR)、误删表恢复案例
各位同学,咱们今天聊点真家伙。备份做得再好,恢复不出来,那就是一堆废纸。我见过太多团队,备份脚本写得花里胡哨,真到恢复的时候,手忙脚乱,甚至数据全丢。说白了,恢复才是备份的最终目的。
这一章,咱们就动手演练。我会带你走一遍全量恢复的标准流程,再讲讲基于时间点的恢复(PITR)怎么玩,最后用一个误删表的真实案例收尾。嗯,都是我在生产环境里踩过的坑,你拿笔记一下。
核心原则:恢复之前,先确认备份文件完整、可用。别等到跑了一半才发现备份坏了,那才叫欲哭无泪。
一、全量恢复流程:稳扎稳打
全量恢复,说白了就是把之前备份的完整数据文件,原封不动地倒回去。听起来简单,但步骤不能乱。我习惯按这个顺序来:
- 停服务 —— 先把数据库停掉,或者至少把应用连接断开。你想想看,一边恢复一边写数据,那不乱套了吗?
- 清数据目录 —— 把当前的数据目录清空,或者挪走。注意,别手滑删错了地方。
- 解压备份文件 —— 把之前打包的备份文件解压到数据目录。
- 修改权限 —— 确保文件属主是 mysql 用户,不然启动会报错。
- 启动数据库 —— 启动后检查错误日志,确认没有异常。
- 验证数据 —— 随便查几条记录,看看数据对不对。
我的习惯:恢复完成后,我会立刻做一次全量备份。为什么?因为恢复过程中可能产生新的日志,万一后面还要恢复,这个备份就是新的起点。
给你看个 MySQL 全量恢复的典型命令:
# 1. 停止数据库
systemctl stop mysqld
# 2. 备份当前数据目录(以防万一)
mv /var/lib/mysql /var/lib/mysql_bak
# 3. 创建新数据目录
mkdir -p /var/lib/mysql
# 4. 解压备份文件
tar -xzf /backup/full_backup_2024-01-15.tar.gz -C /var/lib/mysql/
# 5. 修改权限
chown -R mysql:mysql /var/lib/mysql
# 6. 启动数据库
systemctl start mysqld
# 7. 检查状态
mysql -e "SELECT COUNT(*) FROM information_schema.tables;"
嗯,这里要注意:如果你的备份是 mysqldump 导出的 SQL 文件,那恢复方式就不一样了。直接用 mysql < backup.sql 导入就行。但如果是物理备份(比如 XtraBackup),就得按上面的步骤来。
二、基于时间点的恢复(PITR):精确到秒
全量恢复只能恢复到备份的那个时间点。但很多时候,我们需要恢复到备份之后的某个时刻。比如,你凌晨 2 点做了备份,结果早上 10 点有人误操作删了数据。这时候,PITR 就派上用场了。
PITR 的原理,说白了就是:先恢复全量备份,再应用备份之后的 binlog,直到目标时间点。
我曾经帮一个客户恢复过数据。他们下午 3 点误删了一张核心表,全量备份是凌晨 2 点做的。我用了 PITR,精确恢复到了下午 2:59:59 的状态。嗯,数据一条没丢。
具体步骤:
- 恢复最近一次全量备份。
- 找到全量备份之后的所有 binlog 文件。
- 用
mysqlbinlog工具,把 binlog 解析成 SQL,并指定停止时间点。 - 把解析出来的 SQL 导入数据库。
命令示例:
# 第一步:恢复全量备份(略,参考上一节)
# 第二步:查看 binlog 列表
mysql -e "SHOW BINARY LOGS;"
# 第三步:解析 binlog 到目标时间点
mysqlbinlog --stop-datetime="2024-01-15 14:59:59" \
/var/lib/mysql/binlog.000012 \
/var/lib/mysql/binlog.000013 \
/var/lib/mysql/binlog.000014 \
> /tmp/pitr_recovery.sql
# 第四步:导入恢复数据
mysql -u root -p < /tmp/pitr_recovery.sql
重要提醒:PITR 的前提是 binlog 必须完整。如果 binlog 文件损坏或丢失,那神仙也救不了。所以,binlog 的备份和全量备份一样重要。
三、误删表恢复案例:实战复盘
好了,咱们来点刺激的。假设你正在值班,突然收到报警:核心业务表 orders 被删了。你怎么办?
别慌。我经历过类似的事,当时心跳直接飙到 120。但越是这种时候,越要冷静。按步骤来:
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | 立即锁定数据库 | 防止新的写入覆盖 binlog 或数据块 |
| 2 | 确认误删时间 | 从应用日志或 binlog 中找到精确时间点 |
| 3 | 恢复全量备份 | 恢复到误删之前的最近一次全量备份 |
| 4 | 应用 binlog 到误删前一刻 | 使用 --stop-datetime 精确控制 |
| 5 | 导出误删的表 | 从恢复的实例中导出 orders 表 |
| 6 | 导入生产环境 | 将表导入原数据库,注意不要覆盖其他数据 |
这里有个关键点:不要直接在原库上恢复。我建议另起一个实例做恢复,然后把需要的表导出来,再导入生产库。这样最安全。
给你看个实际操作的片段:
# 在另一台机器上恢复全量备份
# 假设备份文件在 /backup/full_20240115.sql
mysql -u root -p < /backup/full_20240115.sql
# 应用 binlog 到误删前一刻(假设误删时间是 10:05:00)
mysqlbinlog --stop-datetime="2024-01-16 10:04:59" \
/backup/binlog.000015 \
| mysql -u root -p
# 导出误删的表
mysqldump -u root -p mydb orders > /tmp/orders_recovery.sql
# 导入生产环境
mysql -u root -p mydb < /tmp/orders_recovery.sql
避坑指南:我曾经遇到过一次,binlog 里混杂了其他库的 DDL 语句,导致恢复时把别的表结构也改了。所以,用 mysqlbinlog 时,最好加上 --database=mydb 参数,只恢复指定库的日志。
四、恢复后的验证:别急着走
数据恢复完了,不代表万事大吉。我见过有人恢复完就跑,结果第二天发现数据对不上。嗯,验证这一步,不能省。
我一般会做这几件事:
- 行数对比 —— 用
SELECT COUNT(*)对比恢复前后的记录数。 - 关键业务数据抽查 —— 找几条最近的订单,核对金额、状态。
- 检查自增 ID —— 有时候恢复会导致自增 ID 错乱,需要手动调整。
- 通知业务方验证 —— 让业务同事跑几个核心功能,确认没问题。
我的习惯:恢复完成后,我会立刻做一次全量备份,并保留恢复过程中的所有日志。这样,万一后续发现问题,还能回溯。
好了,这一章的内容就到这里。全量恢复、PITR、误删表恢复,这三个场景基本覆盖了日常工作中 90% 的恢复需求。你回去之后,最好在测试环境里亲手演练几遍。只有亲手做过,心里才有底。