人人都会AI编程

18.3 XtraBackup 物理热备份与恢复

更新时间:2026-07-10

mysqldump 逻辑备份虽然简单易用,但在数据量达到上百 GB 甚至 TB 级别时,导出导入的耗时会长到难以接受,而且备份期间对生产库的压力也不小。对于大规模数据库,物理备份是更务实的选择,而 Percona XtraBackup 正是社区公认的物理热备份事实标准。

18.3.1 XtraBackup 是什么,解决什么问题

XtraBackup 是 Percona 公司开源的 MySQL / MariaDB 物理热备份工具。所谓物理,就是直接复制数据文件,而不是把数据转换成 SQL 语句;所谓热备,就是在数据库正常运行、读写不中断的情况下完成备份,不需要锁表或停机。

它的核心优势很直接:

  • 备份速度快:直接拷贝数据页,性能上限通常是磁盘 I/O 本身的速度,远超逻辑导出。
  • 对业务影响小:仅在备份开始和结束时短暂加锁(或利用备份锁 8.0),整个过程数据库可以正常读写。
  • 支持在线恢复:基于备份文件可以直接启动 MySQL 实例或恢复到任意时间点。
  • 增量备份:在全量备份基础上,只备份自上一次备份以来变化的数据页,大幅节省时间和空间。
  • 压缩与流式备份:备份数据可以直接压缩输出,或通过网络流式传输到远程存储,适应不同备份方案。

对于数据量超过 50 GB 的生产库,XtraBackup 几乎是物理备份的唯一推荐选择。许多云厂商的数据库备份服务,底层也用到了 XtraBackup 或类似原理。

18.3.2 工作原理简述

XtraBackup 的核心是两个线程的配合:拷贝线程Redo Log 监控线程

  1. 备份开始时,XtraBackup 先记录当前的 Log Sequence Number(LSN,日志序列号),然后启动一个后台线程持续监控 InnoDB 的 Redo Log 文件,将新写入的日志拉取到备份目录。
  2. 同时,主线程开始拷贝 InnoDB 的数据文件(.ibdibdata1)和表结构文件(.frm 或 8.0 的 *.sdi)。
  3. 在拷贝过程中,数据库的写入也在进行。被修改过的数据页可能来不及被拷贝到备份,或者拷贝到一半就被改了。这会导致直接拷贝出来的文件是一个“不一致的”数据。这时,第一步中持续拉取的 Redo Log 就发挥作用了。
  4. 拷贝完成后,XtraBackup 进入准备阶段(--prepare)。它会利用拉取的 Redo Log,重放已提交的事务,回滚未提交的事务,最终生成一个数据一致性状态。这个过程相当于对备份做了一次崩溃恢复。

对于非 InnoDB 的表(如 MyISAM),XtraBackup 会在备份即将结束时短暂执行 FLUSH TABLES WITH READ LOCK 获取全局读锁,拷贝这些表,然后释放锁。如果是全 InnoDB 环境,这个锁几乎可以忽略不计,而利用 MySQL 8.0 的备份锁特性,这个锁定过程还能进一步优化。

18.3.3 安装与版本选择

XtraBackup 有两个大版本系列:

  • XtraBackup 8.0:适用于 MySQL 8.0 和 Percona Server for MySQL 8.0。
  • XtraBackup 2.4:适用于 MySQL 5.7 和 MySQL 5.6。

安装方式非常直接,以 CentOS 为例:

# 安装 Percona 官方 yum 源
yum install https://repo.percona.com/yum/percona-release-latest.noarch.rpm -y
# 启用工具仓库
percona-release enable-only tools release
# 安装 XtraBackup 80
yum install percona-xtrabackup-80 -y

也可通过压缩包或 Docker 方式运行,但最重要的是 XtraBackup 的版本必须与 MySQL 的大版本严格对应,否则备份或恢复时可能出现数据页格式不兼容的错误。

18.3.4 全量备份与恢复实战

全量备份

备份命令非常简单,只需指定备份目标的目录和一个有足够权限的数据库用户:

xtrabackup --backup \
  --user=root --password='your_password' \
  --target-dir=/backup/full/2024-01-01

执行时屏幕上会输出拷贝进度和 LSN 信息。备份完成后,/backup/full/2024-01-01 目录下会包含数据库的所有数据文件以及 XtraBackup 的元数据文件 xtrabackup_checkpoints

为了减少备份占用空间,通常会结合压缩和流式输出:

xtrabackup --backup \
  --user=root --password='your_password' \
  --compress --compress-threads=4 \
  --target-dir=/backup/full/2024-01-01

使用 --compress 后,数据页文件会以 .qp 压缩格式存放,后续恢复时需要先解压。

生产环境中更常见的做法是直接流式备份并远程传输:

xtrabackup --backup \
  --user=root --password='your_password' \
  --stream=xbstream | gzip > /backup/full_20240101.xb.gz

这种方式不产生中间目录,直接生成一个压缩包,非常便于上传到对象存储。

全量恢复

恢复分为两步:准备和恢复。

  1. 准备阶段(--prepare:把备份目录变为一致状态。如果备份时使用了压缩,需要先解压。
# 解压(如果压缩备份)
xtrabackup --decompress --target-dir=/backup/full/2024-01-01

# 准备备份
xtrabackup --prepare --target-dir=/backup/full/2024-01-01

准备过程中,XtraBackup 会应用 Redo Log,使数据文件达到一致状态。对于全量备份,这一步通常较快。

  1. 恢复阶段:将准备好的数据文件拷回 MySQL 数据目录。

必须先停止 MySQL 服务,清空(或移走)原有数据目录,然后再执行恢复:

systemctl stop mysql
# 备份原有数据目录(强烈建议)
mv /var/lib/mysql /var/lib/mysql_backup
# 恢复
xtrabackup --copy-back --target-dir=/backup/full/2024-01-01
# 更改权限(重要!)
chown -R mysql:mysql /var/lib/mysql
# 启动
systemctl start mysql

--copy-back 会将备份目录下所有文件按原始路径复制回 MySQL 的 datadir。这一步完成后数据库就恢复到了备份时刻的状态。

18.3.5 增量备份与恢复

增量备份可以极大缩短备份窗口和存储开销,尤其适用于每天一次全备、小时级增量备的常规策略。

增量备份基于全量备份或上一次增量备份执行。用法是在 --backup 基础上指定 --incremental--incremental-basedir,后者指向上一次备份的目录。

# 第一次增量:基于全量备份
xtrabackup --backup \
  --user=root --password='your_password' \
  --target-dir=/backup/inc1/2024-01-02 \
  --incremental-basedir=/backup/full/2024-01-01

# 第二次增量:基于上一次增量备份
xtrabackup --backup \
  --user=root --password='your_password' \
  --target-dir=/backup/inc2/2024-01-03 \
  --incremental-basedir=/backup/inc1/2024-01-02

增量备份仅包含自 incremental-basedir 以来修改的数据页,因此大小远小于全量备份,备份速度也很快。

增量恢复需要把所有的增量备份按顺序合并到全量备份中,然后再恢复。

# 1. 准备全量备份(只应用 committed 事务,不回滚)
xtrabackup --prepare --apply-log-only --target-dir=/backup/full/2024-01-01

# 2. 合并第一个增量备份到全量备份
xtrabackup --prepare --apply-log-only \
  --target-dir=/backup/full/2024-01-01 \
  --incremental-dir=/backup/inc1/2024-01-02

# 3. 合并第二个增量备份(最后一个增量不加 --apply-log-only)
xtrabackup --prepare \
  --target-dir=/backup/full/2024-01-01 \
  --incremental-dir=/backup/inc2/2024-01-03

# 4. 最后再执行一次 --prepare 完成回滚
xtrabackup --prepare --target-dir=/backup/full/2024-01-01

# 5. 停库,恢复数据(同全量恢复)
systemctl stop mysql
mv /var/lib/mysql /var/lib/mysql_backup
xtrabackup --copy-back --target-dir=/backup/full/2024-01-01
chown -R mysql:mysql /var/lib/mysql
systemctl start mysql

在合并过程中,除最后一次外都必须使用 --apply-log-only,目的是让 XtraBackup 只应用重做日志而不执行回滚,否则后面的增量备份就无法继续合并了。最后一次增量合并完成后再执行一次不带 --apply-log-only--prepare,让回滚阶段完成,保证数据一致性。

18.3.6 备份策略与最佳实践

结合前面所学的知识,一套经得起考验的物理备份策略通常包含以下几条原则:

  1. 坚持全量 + 增量循环:每周或每日一次全量备份,然后以小时或天为单位做增量备份。例如:每周日凌晨全备,每天凌晨增量备,可以大幅减少备份时间。
  2. 备份文件流远程存储,不是本地堆积:备份文件必须存放在与数据库不同的物理机器或对象存储上,防止主机故障时备份和数据库一块丢。
  3. 定期进行恢复演练:至少每个月在没有业务依赖的环境下做一次完整恢复测试,确保备份有效、恢复流程可执行。许多公司等到真出事才发现备份文件已损坏。
  4. 配合 Binlog 实现秒级恢复:物理备份只能恢复到某个时间点,如果希望恢复至故障发生前那一刻,需要配合 Binlog 的 mysqlbinlog 从备份时间点开始回放。XtraBackup 备份完成后会记录当时的 Binlog 文件名和位置,供后续精确点恢复使用。
  5. 控制备份对线上影响:设置 --use-memory 参数限制 prepare 阶段的内存使用;备份时间避开业务高峰,并监控备份期间的 IO 和连接并发。

XtraBackup 是运维工具箱中不可或缺的一环。它的存在让“随时能从物理备份中完整恢复数据”从理论变成了简单的几个命令,真正做到了生产级的数据保护。