MySQL 完全指南 / 第 13 章:备份恢复
第 13 章:备份恢复
没有备份的数据库就像没有安全网的高空走钢丝。本章详解备份策略与恢复方法。
13.1 备份策略总览
| 类型 | 工具 | 速度 | 锁定 | 适用场景 |
|---|
| 逻辑备份 | mysqldump | 中等 | 可选 | 小中型数据库、跨版本迁移 |
| 物理备份 | xtrabackup | 快 | 不锁表 | 大型数据库、PITR |
| 快照备份 | LVM/ZFS 快照 | 极快 | 短暂 | 文件系统支持快照的环境 |
| Binlog 备份 | mysqlbinlog | — | 不锁表 | 增量备份、PITR |
13.2 mysqldump 逻辑备份
13.2.1 基本备份
# 备份单个数据库
mysqldump -uroot -p --single-transaction myapp > myapp_backup.sql
# 备份多个数据库
mysqldump -uroot -p --single-transaction --databases myapp auth > multi_db_backup.sql
# 备份所有数据库
mysqldump -uroot -p --single-transaction --all-databases > all_backup.sql
# 备份指定表
mysqldump -uroot -p --single-transaction myapp users orders > tables_backup.sql
# 只备份表结构(不含数据)
mysqldump -uroot -p --no-data myapp > schema_backup.sql
# 只备份数据(不含结构)
mysqldump -uroot -p --no-create-info myapp > data_backup.sql
13.2.2 推荐参数
mysqldump -uroot -p \
--single-transaction \ # InnoDB 不锁表(一致性快照)
--routines \ # 包含存储过程和函数
--triggers \ # 包含触发器
--events \ # 包含事件调度器
--set-gtid-purged=ON \ # GTID 环境下使用
--hex-blob \ # BLOB 数据用十六进制
--default-character-set=utf8mb4 \
--result-file=/backup/myapp_$(date +%Y%m%d_%H%M%S).sql \
myapp
| 参数 | 说明 |
|---|
--single-transaction | InnoDB 一致性备份,不锁表 |
--routines | 备份存储过程和函数 |
--triggers | 备份触发器 |
--events | 备份事件调度器 |
--set-gtid-purged | GTID 环境下控制 GTID 信息 |
--flush-logs | 备份前切换 Binlog |
--master-data=2 | 记录 Binlog 位置(注释形式) |
--hex-blob | 二进制数据用十六进制 |
--max-allowed-packet | 最大包大小 |
13.2.3 恢复
# 恢复数据库
mysql -uroot -p myapp < myapp_backup.sql
# 恢复所有数据库
mysql -uroot -p < all_backup.sql
# 在 MySQL 命令行中恢复
# mysql> SOURCE /backup/myapp_backup.sql;
13.2.4 压缩备份
# 压缩备份
mysqldump -uroot -p --single-transaction myapp | gzip > myapp_$(date +%Y%m%d).sql.gz
# 压缩恢复
gunzip < myapp_20260510.sql.gz | mysql -uroot -p myapp
13.3 XtraBackup 物理备份
13.3.1 安装
# Ubuntu/Debian
sudo apt install percona-xtrabackup-80
# CentOS/RHEL
sudo yum install percona-xtrabackup-80
13.3.2 全量备份
# 全量备份
xtrabackup --backup \
--target-dir=/backup/full \
--user=root --password='MyPassword'
# 准备备份(应用 Redo Log)
xtrabackup --prepare --target-dir=/backup/full
# 恢复
systemctl stop mysql
rm -rf /var/lib/mysql/*
xtrabackup --copy-back --target-dir=/backup/full --datadir=/var/lib/mysql
chown -R mysql:mysql /var/lib/mysql
systemctl start mysql
13.3.3 增量备份
# 第 1 步:全量备份
xtrabackup --backup --target-dir=/backup/full --user=root --password='MyPassword'
# 第 2 步:增量备份(基于全量)
xtrabackup --backup \
--target-dir=/backup/inc1 \
--incremental-basedir=/backup/full \
--user=root --password='MyPassword'
# 第 3 步:第二次增量备份(基于第一次增量)
xtrabackup --backup \
--target-dir=/backup/inc2 \
--incremental-basedir=/backup/inc1 \
--user=root --password='MyPassword'
# 恢复增量备份
# 1. 准备全量备份(不回滚未提交事务)
xtrabackup --prepare --apply-log-only --target-dir=/backup/full
# 2. 应用第一次增量
xtrabackup --prepare --apply-log-only --target-dir=/backup/full --incremental-dir=/backup/inc1
# 3. 应用第二次增量
xtrabackup --prepare --target-dir=/backup/full --incremental-dir=/backup/inc2
# 4. 恢复
xtrabackup --copy-back --target-dir=/backup/full --datadir=/var/lib/mysql
13.4 Binlog 增量备份与 PITR
13.4.1 Binlog 备份
# 备份 Binlog
mysqlbinlog --read-from-remote-server --raw \
--host=192.168.1.100 --user=root --password='MyPassword' \
--result-file=/backup/binlog/ \
mysql-bin.000001 mysql-bin.000002 mysql-bin.000003
# 自动备份脚本
mysqlbinlog --read-from-remote-server --raw \
--host=192.168.1.100 --user=repl --password='ReplPass' \
--result-file=/backup/binlog/ \
--start-position=4 --stop-never mysql-bin.000001 &
13.4.2 时间点恢复(PITR)
# 场景:误删数据,恢复到 2026-05-10 14:30:00
# 1. 恢复最近的全量备份
mysql -uroot -p myapp < /backup/myapp_full_20260510.sql
# 2. 重放 Binlog 到指定时间点(跳过误操作)
mysqlbinlog --start-datetime="2026-05-10 00:00:00" \
--stop-datetime="2026-05-10 14:29:59" \
/var/lib/mysql/mysql-bin.000005 | mysql -uroot -p
# 或使用位置
mysqlbinlog --start-position=154 --stop-position=8910 \
/var/lib/mysql/mysql-bin.000005 | mysql -uroot -p
# 3. 跳过误操作后,继续重放后续 Binlog
mysqlbinlog --start-position=8911 \
/var/lib/mysql/mysql-bin.000005 \
/var/lib/mysql/mysql-bin.000006 | mysql -uroot -p
13.4.3 查看 Binlog 内容
# 查看 Binlog 事件
mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000005 | less
# 查找误操作的位置
mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000005 | grep -B5 -A5 "DELETE FROM users"
13.5 备份自动化脚本
#!/bin/bash
# mysql_backup.sh - MySQL 自动备份脚本
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=7
MYSQL_USER="root"
MYSQL_PASS="MyPassword"
DATABASE="myapp"
# 创建备份目录
mkdir -p ${BACKUP_DIR}
# 全量备份
mysqldump -u${MYSQL_USER} -p${MYSQL_PASS} \
--single-transaction --routines --triggers --events \
--set-gtid-purged=ON \
--result-file=${BACKUP_DIR}/${DATABASE}_${DATE}.sql \
${DATABASE}
# 压缩
gzip ${BACKUP_DIR}/${DATABASE}_${DATE}.sql
# 删除过期备份
find ${BACKUP_DIR} -name "*.sql.gz" -mtime +${RETENTION_DAYS} -delete
echo "Backup completed: ${BACKUP_DIR}/${DATABASE}_${DATE}.sql.gz"
13.6 备份验证
# 定期验证备份有效性
#!/bin/bash
# verify_backup.sh
# 1. 恢复到测试实例
mysql -h test-host -uroot -ptest_pass < /backup/latest_backup.sql
# 2. 检查表完整性
mysql -h test-host -uroot -ptest_pass -e "
SELECT TABLE_NAME, TABLE_ROWS
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'myapp'
ORDER BY TABLE_ROWS DESC;"
# 3. 抽样查询验证数据
mysql -h test-host -uroot -ptest_pass -e "
SELECT COUNT(*) FROM myapp.users;
SELECT COUNT(*) FROM myapp.orders;"
⚠️ 备份黄金法则:
- 3-2-1 原则:至少 3 份备份、2 种介质、1 份异地
- 定期验证备份可恢复性
- 恢复演练比备份更重要
业务场景
场景 1:生产环境备份策略
| 时间 | 操作 | 保留时间 |
|---|
| 每天凌晨 2:00 | xtrabackup 全量备份 | 7 天 |
| 每小时 | Binlog 备份 | 3 天 |
| 每周日 | mysqldump 逻辑备份到异地 | 30 天 |
扩展阅读