MySQL备份恢复策略:mysqldump、XtraBackup与binlog实战
一、概述
1.1 背景介绍
备份是数据库运维中最重要也最容易被忽视的环节。"重要"体现在数据丢失时备份是唯一的救命稻草,"忽视"体现在很多团队有备份脚本但从未做过恢复演练,等到真正需要恢复时才发现备份文件损坏或恢复流程不熟悉。
MySQL 的备份策略需要在 RTO(恢复时间目标)、RPO(恢复点目标)和备份成本之间做权衡。没有一种方案能同时满足"备份快、恢复快、存储小",选型时必须明确业务对这三个维度的优先级。
1.2 技术特点
mysqldump:逻辑备份,SQL 文本格式,可读性强,跨版本兼容,适合小库
XtraBackup:物理备份,直接复制 InnoDB 数据文件,速度快,支持增量,适合大库
binlog:增量日志,配合全量备份实现 PITR(Point-in-Time Recovery),将 RPO 降到分钟级
1.3 适用场景
mysqldump:数据库总量 < 50GB,需要跨版本迁移,或需要备份特定表
XtraBackup:数据库总量 > 50GB,需要快速恢复,或需要搭建从库
binlog PITR:对 RPO 要求严格(< 5 分钟),需要恢复到任意时间点
1.4 环境要求
| 组件 | 版本要求 | 说明 |
|---|---|---|
| MySQL | 8.4.x LTS | XtraBackup 需要版本匹配 |
| XtraBackup | 8.4.x | 必须与 MySQL 大版本一致 |
| 操作系统 | Ubuntu 22.04+ / CentOS 8+ | 推荐 Ubuntu 22.04 |
| 存储空间 | 数据目录 2-3 倍 | 全量备份 + 增量备份空间 |
| 网络 | 备份服务器与 DB 同机房 | 减少备份传输时间 |
二、详细步骤
2.1 三种备份方式对比
| 维度 | mysqldump | XtraBackup | binlog |
|---|---|---|---|
| 备份类型 | 逻辑备份 | 物理备份 | 增量日志 |
| 备份速度 | 慢(需读取所有数据) | 快(文件级复制) | 实时 |
| 恢复速度 | 慢(需重新执行 SQL) | 快(直接替换文件) | 需配合全量 |
| 备份大小 | 压缩后较小 | 与数据目录相当 | 取决于写入量 |
| 一致性 | 需要 --single-transaction | 热备,不锁表 | 需要全量基准 |
| 跨版本 | 支持 | 不支持 | 不支持 |
| 适用库大小 | < 50GB | 任意大小 | 配合全量使用 |
2.2 mysqldump 配置与使用
2.2.1 核心参数详解
# 生产环境标准备份命令
mysqldump
--host=127.0.0.1
--port=3306
--user=backup_user
--password="${BACKUP_PASS}"
--single-transaction # InnoDB 一致性快照,不锁表(关键参数)
--master-data=2 # 记录 binlog position,注释形式写入备份文件
--source-data=2 # 8.4 中替代 --master-data
--flush-logs # 备份前切换 binlog,便于后续 PITR
--hex-blob # BLOB 字段用十六进制,避免字符集问题
--routines # 备份存储过程和函数
--triggers # 备份触发器
--events # 备份定时事件
--compress # 客户端与服务端传输压缩
--databases production_db
| gzip -9 > /backup/mysql/production_db_$(date +%Y%m%d_%H%M%S).sql.gz
2.2.2 备份账号权限
-- 创建最小权限备份账号 CREATEUSER'backup_user'@'127.0.0.1' IDENTIFIEDWITHcaching_sha2_passwordBY'BackupPass@2024'; GRANTSELECT,SHOWVIEW,TRIGGER,LOCKTABLES, REPLICATIONCLIENT, PROCESS,EVENT ON*.*TO'backup_user'@'127.0.0.1'; -- 8.4 中 REPLICATION CLIENT 已改名为 REPLICATION_CLIENT_ADMIN -- 但旧名称仍兼容 FLUSHPRIVILEGES;
2.2.3 恢复流程
# 解压并恢复 gunzip < /backup/mysql/production_db_20240115_020000.sql.gz | mysql -u root -p production_db # 查看备份文件中的 binlog position(用于 PITR) zcat /backup/mysql/production_db_20240115_020000.sql.gz | grep "CHANGE MASTER|CHANGE REPLICATION SOURCE" | head -5 # 输出示例: # -- CHANGE REPLICATION SOURCE TO SOURCE_LOG_FILE='mysql-bin.000123', SOURCE_LOG_POS=4567890;
2.3 XtraBackup 全量 + 增量备份
2.3.1 安装 XtraBackup 8.4
# Ubuntu 22.04 wget https://downloads.percona.com/downloads/percona-xtrabackup-8.4/ percona-xtrabackup-8.4.0-1/binary/debian/jammy/x86_64/ percona-xtrabackup-84_8.4.0-1.jammy_amd64.deb dpkg -i percona-xtrabackup-84_8.4.0-1.jammy_amd64.deb apt-get install -f # 安装依赖
2.3.2 全量备份
# 全量备份
xtrabackup
--backup
--user=backup_user
--password="${BACKUP_PASS}"
--host=127.0.0.1
--target-dir=/backup/xtrabackup/full_$(date +%Y%m%d)
--compress # 压缩备份文件
--compress-threads=4 # 压缩并行线程数
--parallel=4 # 备份并行线程数
--slave-info # 如果是从库,记录主库 binlog position
--safe-slave-backup # 从库备份时暂停复制,确保一致性
# 备份完成后准备(prepare)阶段
# prepare 阶段将 redo log 应用到数据文件,使备份达到一致状态
xtrabackup
--prepare
--target-dir=/backup/xtrabackup/full_20240115
2.3.3 增量备份
# 基于全量备份做第一次增量
xtrabackup
--backup
--user=backup_user
--password="${BACKUP_PASS}"
--target-dir=/backup/xtrabackup/inc_$(date +%Y%m%d_%H)
--incremental-basedir=/backup/xtrabackup/full_20240115
--compress
--compress-threads=4
--parallel=4
# 基于上一次增量做第二次增量
xtrabackup
--backup
--user=backup_user
--password="${BACKUP_PASS}"
--target-dir=/backup/xtrabackup/inc_20240115_12
--incremental-basedir=/backup/xtrabackup/inc_20240115_06
--compress
--compress-threads=4
2.3.4 增量备份恢复流程
# 步骤 1:准备全量备份(不应用 redo log,等待增量合并) xtrabackup --prepare --apply-log-only --target-dir=/backup/xtrabackup/full_20240115 # 步骤 2:合并第一个增量到全量 xtrabackup --prepare --apply-log-only --target-dir=/backup/xtrabackup/full_20240115 --incremental-dir=/backup/xtrabackup/inc_20240115_06 # 步骤 3:合并最后一个增量(去掉 --apply-log-only,应用 redo log) xtrabackup --prepare --target-dir=/backup/xtrabackup/full_20240115 --incremental-dir=/backup/xtrabackup/inc_20240115_12 # 步骤 4:停止 MySQL,恢复数据文件 systemctl stop mysql mv /var/lib/mysql /var/lib/mysql.bak xtrabackup --copy-back --target-dir=/backup/xtrabackup/full_20240115 chown -R mysql:mysql /var/lib/mysql systemctl start mysql
2.4 binlog PITR(基于时间点恢复)
2.4.1 前提条件
# MySQL 必须开启 binlog [mysqld] log_bin = /var/log/mysql/mysql-bin binlog_format = ROW expire_logs_days = 0 # 不自动删除,由备份脚本管理 binlog_expire_logs_seconds = 604800 # 7 天,8.4 推荐用这个参数
2.4.2 PITR 恢复流程
# 场景:全量备份时间 2024-01-15 0200,误操作发生在 1000
# 目标:恢复到 1059
# 步骤 1:恢复全量备份(mysqldump 方式)
gunzip < /backup/mysql/production_db_20240115_020000.sql.gz
| mysql -u root -p production_db
# 步骤 2:从备份文件获取 binlog position
BINLOG_FILE="mysql-bin.000123"
BINLOG_POS=4567890
# 步骤 3:应用 binlog 到误操作前一刻
mysqlbinlog
--start-position=${BINLOG_POS}
--stop-datetime="2024-01-15 1059"
--database=production_db
/var/log/mysql/mysql-bin.000123
/var/log/mysql/mysql-bin.000124
| mysql -u root -p production_db
# 如果需要跳过某个误操作事务(已知 GTID)
mysqlbinlog
--start-position=${BINLOG_POS}
--stop-datetime="2024-01-15 1059"
--exclude-gtids="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:12345"
/var/log/mysql/mysql-bin.000123
| mysql -u root -p production_db
三、示例代码和配置
3.1 自动化备份脚本
#!/bin/bash # 文件名:mysql-backup.sh # 功能:MySQL 全量备份 + binlog 归档,支持本地和远程存储 set-euo pipefail # 配置 MYSQL_USER="backup_user" MYSQL_PASS="${MYSQL_BACKUP_PASS}"# 从环境变量读取,不硬编码 MYSQL_HOST="127.0.0.1" BACKUP_BASE="/backup/mysql" BINLOG_DIR="/var/log/mysql" REMOTE_BUCKET="s3://company-mysql-backup" RETENTION_DAYS=7 DATE=$(date +%Y%m%d_%H%M%S) LOG_FILE="/var/log/mysql-backup.log" log() { echo"[$(date '+%Y-%m-%d %H:%M:%S')] $*"| tee -a"${LOG_FILE}" } # 全量备份 full_backup() { localbackup_file="${BACKUP_BASE}/full_${DATE}.sql.gz" log"开始全量备份:${backup_file}" mysqldump --host="${MYSQL_HOST}" --user="${MYSQL_USER}" --password="${MYSQL_PASS}" --single-transaction --source-data=2 --flush-logs --hex-blob --routines --triggers --events --all-databases 2>>"${LOG_FILE}" | gzip -6 >"${backup_file}" localsize size=$(du -sh"${backup_file}"| cut -f1) log"全量备份完成,大小:${size}" # 上传到对象存储 aws s3 cp"${backup_file}""${REMOTE_BUCKET}/full/" --storage-class STANDARD_IA 2>>"${LOG_FILE}" log"备份已上传到 S3" } # binlog 归档 archive_binlog() { log"开始归档 binlog" # 切换到新的 binlog 文件 mysql --host="${MYSQL_HOST}" --user="${MYSQL_USER}" --password="${MYSQL_PASS}" -e"FLUSH BINARY LOGS;"2>>"${LOG_FILE}" # 获取当前 binlog 文件列表(排除最新的,它还在写入) localcurrent_binlog current_binlog=$(mysql --host="${MYSQL_HOST}" --user="${MYSQL_USER}" --password="${MYSQL_PASS}" -sNe"SHOW MASTER STATUS"2>>"${LOG_FILE}"| awk'{print $1}') # 上传除当前文件外的所有 binlog forbinlogin"${BINLOG_DIR}"/mysql-bin.[0-9]*;do localfilename filename=$(basename"${binlog}") if[["${filename}"!="${current_binlog}"]];then aws s3 cp"${binlog}""${REMOTE_BUCKET}/binlog/" --storage-class STANDARD_IA 2>>"${LOG_FILE}"&& log"已归档:${filename}" fi done } # 清理过期备份 cleanup_old_backups() { log"清理${RETENTION_DAYS}天前的本地备份" find"${BACKUP_BASE}"-name"full_*.sql.gz" -mtime"+${RETENTION_DAYS}"-delete } # 备份验证(随机抽查) verify_backup() { locallatest_backup latest_backup=$(ls -t"${BACKUP_BASE}"/full_*.sql.gz | head -1) log"验证备份文件:${latest_backup}" # 检查文件完整性 ifgzip -t"${latest_backup}"2>>"${LOG_FILE}";then log"备份文件完整性验证通过" else log"ERROR: 备份文件损坏!" exit1 fi # 检查备份文件包含关键表 ifzcat"${latest_backup}"| grep -q"CREATE TABLE.*orders";then log"关键表验证通过" else log"ERROR: 备份文件缺少关键表!" exit1 fi } main() { mkdir -p"${BACKUP_BASE}" log"=== MySQL 备份开始 ===" full_backup archive_binlog verify_backup cleanup_old_backups log"=== MySQL 备份完成 ===" } main"$@"
3.2 恢复演练脚本
#!/bin/bash
# 文件名:mysql-restore-test.sh
# 功能:在测试环境验证备份可恢复性
BACKUP_FILE=$1
TEST_DB="restore_test_$(date +%Y%m%d)"
MYSQL_ROOT_PASS="${MYSQL_ROOT_PASS}"
if[[ -z"${BACKUP_FILE}"]];then
echo"用法:$0"
exit1
fi
echo"创建测试数据库:${TEST_DB}"
mysql -u root -p"${MYSQL_ROOT_PASS}"-e"CREATE DATABASE${TEST_DB};"
echo"开始恢复备份..."
time gunzip < "${BACKUP_FILE}"
| mysql -u root -p"${MYSQL_ROOT_PASS}" "${TEST_DB}"
echo "验证数据完整性..."
mysql -u root -p"${MYSQL_ROOT_PASS}" "${TEST_DB}" <<'EOF'
-- 检查关键表行数
SELECT table_name, table_rows
FROM information_schema.TABLES
WHERE table_schema = DATABASE()
ORDER BY table_rows DESC
LIMIT 10;
EOF
echo "清理测试数据库"
mysql -u root -p"${MYSQL_ROOT_PASS}" -e "DROP DATABASE ${TEST_DB};"
echo "恢复演练完成"
四、最佳实践和注意事项
4.1 最佳实践
4.1.1 备份策略设计
根据 RTO/RPO 目标选择备份组合:
| 业务级别 | RPO 目标 | RTO 目标 | 推荐策略 |
|---|---|---|---|
| 核心交易 | < 5 分钟 | < 30 分钟 | XtraBackup 每日全量 + binlog 实时归档 |
| 一般业务 | < 1 小时 | < 2 小时 | mysqldump 每日全量 + binlog 每小时归档 |
| 非关键数据 | < 24 小时 | < 4 小时 | mysqldump 每日全量 |
4.1.2 3-2-1 备份原则
3 份备份:原始数据 + 本地备份 + 远程备份
2 种介质:本地磁盘 + 对象存储(S3/OSS)
1 份异地:备份存储在不同地域,防止机房级故障
4.1.3 备份监控
# 检查备份是否按时完成(Prometheus 告警规则) # 如果最新备份文件超过 25 小时未更新,触发告警 find /backup/mysql -name"full_*.sql.gz"-mmin -1500 | wc -l # 结果为 0 时说明备份失败,需要告警
4.2 注意事项
4.2.1 常见错误
警告:以下错误在生产环境中曾导致数据无法恢复。
mysqldump 不加--single-transaction会锁表,对 InnoDB 表必须加此参数
XtraBackup 版本必须与 MySQL 版本严格匹配,8.0 的 XtraBackup 无法备份 8.4 的 MySQL
binlog 必须在全量备份完成后才能删除,否则 PITR 会有空洞
4.2.2 常见错误排查
| 错误现象 | 原因分析 | 解决方案 |
|---|---|---|
| mysqldump 卡住不动 | 有长事务持有表锁 | SHOW PROCESSLIST 找到长事务并 KILL |
| XtraBackup 报 "redo log archiving" 错误 | MySQL 8.4 新特性冲突 | 升级 XtraBackup 到对应版本 |
| binlog 恢复后数据不一致 | binlog position 记录错误 | 使用 GTID 模式替代 position 模式 |
| 备份文件 gzip 损坏 | 磁盘空间不足导致写入中断 | 备份前检查磁盘空间,设置告警阈值 80% |
| 恢复速度极慢 | innodb_buffer_pool_size 太小 | 恢复时临时调大 buffer pool |
五、故障排查和监控
5.1 备份失败排查
5.1.1 常见问题排查
问题一:mysqldump 连接超时
# 诊断:检查 MySQL 连接状态 mysql -u root -p -e"SHOW STATUS LIKE 'Threads_connected';" mysql -u root -p -e"SHOW PROCESSLIST;"| grep -v Sleep # 解决:增加超时参数 mysqldump --net-read-timeout=3600 --net-write-timeout=3600 ...
问题二:XtraBackup 备份中断
# 查看 XtraBackup 日志 tail -100 /backup/xtrabackup/full_20240115/xtrabackup_info # 常见原因:磁盘空间不足 df -h /backup/ # 检查 MySQL 错误日志 tail -50 /var/log/mysql/error.log
问题三:binlog 文件缺失
-- 查看当前 binlog 列表 SHOWBINARYLOGS; -- 查看 binlog 中的事件(验证内容) SHOWBINLOGEVENTSIN'mysql-bin.000123'LIMIT20; -- 如果 binlog 已被清理,检查 expire 配置 SHOWVARIABLESLIKE'binlog_expire_logs_seconds';
5.2 性能监控
5.2.1 备份性能指标
# 监控备份速度(MB/s) iostat -x 1 | grep -E"Device|sda" # 监控备份进度(XtraBackup) # XtraBackup 会输出已处理的数据量 tail -f /var/log/xtrabackup.log | grep"MB/s" # 监控 mysqldump 进度 # 通过 performance_schema 查看当前执行的 SQL mysql -e"SELECT * FROM performance_schema.processlist WHERE user='backup_user'G"
5.2.2 监控指标说明
| 指标名称 | 正常范围 | 告警阈值 | 说明 |
|---|---|---|---|
| 备份完成时间 | < 4 小时 | > 6 小时 | 超时说明数据量增长或性能下降 |
| 备份文件大小变化 | ±20% | > 50% 增长 | 突增可能是数据异常 |
| binlog 生成速率 | 业务基线 | 基线 3x | 突增可能是大批量写入 |
| 磁盘使用率 | < 70% | > 80% | 备份磁盘空间告警 |
5.3 备份与恢复
5.3.1 定期恢复演练
# 每月执行一次恢复演练,验证备份可用性 # 在测试环境执行,记录恢复时间 # 1. 从 S3 下载最新备份 aws s3 cp s3://company-mysql-backup/full/full_latest.sql.gz /tmp/ # 2. 记录开始时间 START_TIME=$(date +%s) # 3. 执行恢复 gunzip < /tmp/full_latest.sql.gz | mysql -u root -p test_restore_db # 4. 计算恢复时间 END_TIME=$(date +%s) echo "恢复耗时: $((END_TIME - START_TIME)) 秒" # 5. 验证数据 mysql -u root -p test_restore_db -e " SELECT COUNT(*) as order_count FROM orders; SELECT MAX(created_at) as latest_order FROM orders; "
六、总结
6.1 技术要点回顾
方案选型:50GB 以下用 mysqldump,以上用 XtraBackup,两者都需要配合 binlog 实现 PITR
备份验证:备份完成后必须验证文件完整性,每月做一次完整恢复演练
3-2-1 原则:本地 + 远程双份存储,防止单点故障
RTO/RPO 对齐:备份策略必须与业务的恢复目标对齐,不能凭感觉设计
6.2 进阶学习方向
MySQL InnoDB Cluster 内置备份:MySQL Shell 的util.dumpInstance()是 mysqldump 的现代替代品,支持并行导出,速度提升 10 倍以上
Percona XtraBackup 流式备份:直接通过网络流传输到备份服务器,无需本地中转
备份加密:使用--encrypt参数对备份文件加密,满足合规要求
6.3 参考资料
XtraBackup 8.4 官方文档
MySQL 8.4 备份恢复文档
MySQL Shell Dump & Load
附录
A. 命令速查表
# mysqldump 全库备份 mysqldump --single-transaction --source-data=2 --all-databases | gzip > backup.sql.gz # XtraBackup 全量备份 xtrabackup --backup --target-dir=/backup/full --compress --parallel=4 # XtraBackup prepare xtrabackup --prepare --target-dir=/backup/full # 查看 binlog 内容 mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000123 | head -100 # PITR 恢复到指定时间 mysqlbinlog --start-position=4567890 --stop-datetime="2024-01-15 1059"mysql-bin.000123 | mysql -u root -p # 查看备份文件中的 binlog position zcat backup.sql.gz | grep"CHANGE REPLICATION SOURCE"
B. 配置参数详解
| 参数 | 推荐值 | 说明 |
|---|---|---|
| binlog_expire_logs_seconds | 604800 | binlog 保留 7 天 |
| sync_binlog | 1 | 每次提交刷盘,防止 binlog 丢失 |
| innodb_flush_log_at_trx_commit | 1 | 事务提交时刷 redo log |
| max_binlog_size | 1G | 单个 binlog 文件最大 1GB |
C. 术语表
| 术语 | 英文 | 解释 |
|---|---|---|
| 逻辑备份 | Logical Backup | 以 SQL 语句形式备份,可读性强 |
| 物理备份 | Physical Backup | 直接复制数据文件,速度快 |
| 增量备份 | Incremental Backup | 只备份上次备份后变化的数据 |
| PITR | Point-in-Time Recovery | 基于时间点恢复,精确到秒 |
| RTO | Recovery Time Objective | 恢复时间目标,故障到恢复的最长时间 |
| RPO | Recovery Point Objective | 恢复点目标,最多丢失多少数据 |
-
数据库
+关注
关注
7文章
4092浏览量
68676 -
MySQL
+关注
关注
1文章
938浏览量
29851 -
脚本
+关注
关注
1文章
413浏览量
29318
原文标题:MySQL备份恢复策略:mysqldump、XtraBackup与binlog实战
文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
阿里云数据库备份DBS商业化发布,数据库实时备份到OSS
如何用labview对数据库进行备份/如何在MySql中使用命令的方式进行数据库备份(非cmd窗口非手动保存)
基于Linux EXT3的MySQL数据库的数据恢复
数据库数据恢复-数据库文件被删除/分区被格式化的SQL SERVER数据恢复方案
mysql数据库备份与还原
Oracle数据恢复—Oracle数据库delete删除的数据恢复方法
Oracle数据恢复—异常断电后Oracle数据库启库报错的数据恢复案例
MySQL数据库备份恢复方式对比
评论