Xtrabackup8配置MySQL8全量备份及增量备份🥝
使用xtrabackup8配置MySQL8物理备份,包括全量备份及增量备份和恢复备份。
一. 配置全量备份
1.2 配置全量备份命令
bash
[root@localhost ~]# xtrabackup --defaults-file=/etc/xtrabackup.cnf \
--backup \
--target-dir="${FULL_BACKUP_DIR}" \
--parallel="${PARALLEL_THREADS}" \
--compress \
--compress-threads="${COMPRESS_THREADS}" \
--no-server-version-check \
>> "${LOG_FILE}" 2>&1
这段命令是使用 Percona XtraBackup 对 MySQL 进行物理备份的核心指令。
以下是各参数的详细含义解析:
| 参数 | 含义与作用 |
|---|---|
--defaults-file=/etc/xtrabackup.cnf |
指定MySQL配置文件路径 。XtraBackup会读取此文件以获取数据目录位置(datadir)、socket文件路径等信息。更重要的是 ,它通常在此文件中的 [client] 或 [xtrabackup] 段读取数据库连接的用户名(user)和密码(password),避免了在命令行中明文暴露密码。 |
--backup |
执行备份操作的主指令。告诉xtrabackup程序本次要执行的是备份任务。 |
--target-dir="${FULL_BACKUP_DIR}" |
指定备份文件的存储目标目录。所有备份出的数据文件都将放在这个路径下。 |
--parallel="${PARALLEL_THREADS}" |
设置并行拷贝数据文件的线程数。此参数能显著加快大数据库的备份速度,尤其在多核CPU和高速存储(如SSD)环境下效果明显。您设置为CPU核心数的20%。 |
--compress |
启用压缩功能。备份时使用QuickLZ算法对每个数据文件进行压缩,可以大幅减少备份文件所占用的磁盘空间(通常能压缩到原来的1/3到1/4)。 |
--compress-threads="${COMPRESS_THREADS}" |
设置并行压缩 的线程数。与 --parallel 配合,一边拷贝一边压缩,充分利用多核CPU。您设置为CPU核心数的10%。 |
--no-server-version-check |
跳过对MySQL服务器版本的检查。在某些定制化或特定版本的MySQL环境下(如您使用的麒麟系统),避免因版本号匹配问题而产生警告或报错,使备份过程更顺畅。 |
>> "${LOG_FILE}" 2>&1 |
重定向所有输出到日志文件 。>> 表示追加写入日志文件;2>&1 表示将标准错误(stderr)也合并到标准输出(stdout)中,即将屏幕上的所有信息(包括正常信息和错误信息)都记录到日志文件。 |
💡 核心流程梳理:
当你运行这个命令时,XtraBackup 的工作流如下:
-
连接 :根据 --defaults-file 登录 MySQL。
-
拷贝 :开启多个线程 (--parallel) 同时读取数据文件。
-
处理 :读取的数据交给压缩线程 (--compress-threads) 进行实时压缩。
-
持久化 :将处理后的数据写入目标目录 (--target-dir)。
-
收尾 :记录当前的 LSN(日志序列号)到 xtrabackup_checkpoints 文件中。
1.2 编写全量备份脚本
⭐备份过程中涉及用户密码,这里不采用明文配置,使用专门的/etc/xtrabackup.cnf凭据文件。
bash
[root@localhost ~]# vim /etc/xtrabackup.cnf
[client]
user=backup
password=NBJb_sdgfxYhhK6$jfj#
socket=/var/lib/mysql/mysql.sock
[xtrabackup]
datadir=/var/lib/mysql/data
#设置权限
[root@localhost ~]# chmod 600 /etc/xtrabackup.cnf
[root@localhost ~]# chown root:root /etc/xtrabackup.cnf
脚本如下:
bash
[root@localhost ~]# /data/mysql/scripts/xtrabackup_full_backup.sh
#!/bin/bash
#
# ==============================================================================
# MySQL 全量物理备份脚本(基于 Percona XtraBackup)
# 适用于 MySQL 8.0 + 主从环境,优先在从库执行
# 作者:Noleaf 提供,生产可用
# 日期:2025-12-25
#===============================================================================
#设置xtrabackup和MySQL路径,脚本运行时会自动把 MySQL 和 XtraBackup 的路径加入 PATH
export PATH=/usr/local/mysql-8.0.44/bin:/usr/local/percona-xtrabackup-8.0.35/bin:/usr/bin:/bin
# 更安全的错误处理
set -euo pipefail
#=============================变量定义==========================================
#定义时间戳
Timestamp=$(date '+%F_%H-%M-%S')
#备份根目录
BACKUP_BASE=/data/mysql/backup
#物理全量备份根目录
BACKUP_ROOT=${BACKUP_BASE}/physical_full_backup
#备份文件名称
BACKUP_NAME="full_backup_${Timestamp}"
#物理全量备份目录(即实际备份的父目录, 存放各个时间点的全量文件夹)
FULL_BACKUP_DIR=${BACKUP_ROOT}/${BACKUP_NAME}
#日志目录及文件
LOG_DIR=${BACKUP_ROOT}/logs
LOG_FILE=${LOG_DIR}/${BACKUP_NAME}.log
#备份用户(认证凭据采用/etc/xtrabackup.cnf文件)
#MYSQL_USER=backup
#MYSQL_PASS='NBJb_sljfxYhhK6$jfj#'
#控制并行复制数据的线程数(自动计算20%CPU线程数,最小4)
PARALLEL_THREADS=$(($(nproc)*20/100))
[[ $PARALLEL_THREADS -lt 4 ]] && PARALLEL_THREADS=4
#控制并行压缩数据的线程数(自动计算10%CPU线程数,最小2)
COMPRESS_THREADS=$(($(nproc)*10/100))
[[ $COMPRESS_THREADS -lt 2 ]] && COMPRESS_THREADS=2
#定义清理文件时间
KEEP_DAYS=15
echo "==========================创建备份必要的目录======================="
mkdir -p "$BACKUP_ROOT" "$LOG_DIR" "$FULL_BACKUP_DIR" || {
echo "ERROR: 无法创建备份相关目录"
exit 1
}
echo "========================== 物理全量备份开始于 [$Timestamp] ===================" | tee -a "$LOG_FILE"
#1.备份前校验 xtrabackup 是否存在
command -v xtrabackup >/dev/null 2>&1 || {
echo "ERROR: xtrabackup 未安装" | tee -a "$LOG_FILE"
exit 1
}
#2.备份前校验 MySQL 实例是否存活
if ! mysqladmin --defaults-extra-file=/etc/xtrabackup.cnf \
ping --silent; then
echo "ERROR: MySQL 实例不可用,取消备份" | tee -a "$LOG_FILE"
exit 1
fi
#3.执行XtraBackup全量备份
echo "开始执行XtraBackup全量备份到 ${BACKUP_ROOT}..." | tee -a "$LOG_FILE"
if xtrabackup --defaults-file=/etc/xtrabackup.cnf \
--backup \
--target-dir="${FULL_BACKUP_DIR}" \
--parallel="${PARALLEL_THREADS}" \
--compress \
--compress-threads="${COMPRESS_THREADS}" \
--no-server-version-check \
>> "${LOG_FILE}" 2>&1; then
echo "Success: 全量备份成功!" | tee -a "$LOG_FILE"
else
echo "ERROR: 全量备份失败!请检查日志 ${LOG_FILE}" | tee -a "$LOG_FILE"
exit 1
fi
#因使用了set -euo pipefail,有部分冲突,建议使用上面的if语句
#xtrabackup --defaults-file=/etc/xtrabackup.cnf \
# --backup \
# --target-dir=${FULL_BACKUP_DIR} \
# --parallel=${PARALLEL_THREADS} \
# --compress \
# --compress-threads=${COMPRESS_THREADS} \
# --no-server-version-check \
# >> ${LOG_FILE} 2>&1
#
#
#if [ $? -eq 0 ]; then
# echo "Success: 全量备份成功!" | tee -a "$LOG_FILE"
#else
# echo "ERROR: 全量备份失败!请检查日志 ${LOG_FILE}" | tee -a "$LOG_FILE"
# exit 1
#fi
#完成时间不能用上面Timestamp
echo "Full backup completed at $(date '+%F_%H-%M-%S')" >> ${LOG_FILE}
# [重要说明]
# 当前脚本使用了 --compress 生成压缩备份。
# 此时的备份处于 "Raw" 状态,尚未进行 Prepare。
# 恢复时必须先解压,再 Prepare。命令如下:
# 1. xtrabackup --decompress --target-dir=/path/to/backup
# 2. xtrabackup --prepare --target-dir=/path/to/backup
# 3. xtrabackup --copy-back --target-dir=/path/to/backup
#清理15天之前备份
echo "正在清理 $KEEP_DAYS 天之前的旧备份..." | tee -a $LOG_FILE
find "${BACKUP_ROOT}" -maxdepth 1 -type d -name "full_backup*" -mtime +${KEEP_DAYS} -exec rm -rf {} \;
find "${BACKUP_ROOT}/logs" -maxdepth 1 -type f -name "full_backup*" -mtime +${KEEP_DAYS} -exec rm -f {} \;
#统计数据简报
BACKUP_SIZE=$(du -sh "${FULL_BACKUP_DIR}" | cut -f1)
echo "本次备份大小:${BACKUP_SIZE}" | tee -a "$LOG_FILE"
echo "本次备份目录:${FULL_BACKUP_DIR}" | tee -a "$LOG_FILE"
echo "=================== 全量备份完成于 [$(date '+%F %H:%M:%S')] ===================" | tee -a "$LOG_FILE"
1.3 执行脚本
[root@localhost ~]# bash /data/mysql/scripts/xtrabackup_full_backup.sh
==========================创建备份必要的目录=======================
========================== 物理全量备份开始于 [2025-12-29_11-14-05] ===================
mysqld is alive
开始执行XtraBackup全量备份到 /data/mysql/backup/physical_full_backup...
Success: 全量备份成功!
正在清理 15 天之前的旧备份...
本次备份大小:140M
本次备份目录:/data/mysql/backup/physical_full_backup/full_backup_2025-12-29_11-14-05
=================== 全量备份完成于 [2025-12-29 11:14:17] ===================
备份成功!
1.4 加入计划任务
增加到 crontab 定时执行,例如每天凌晨2点:
bash
[root@localhost ~]# crontab -e
0 2 * * * /data/mysql/scripts/xtrabackup_full_backup.sh >> /var/log/xtrabackup_full_backup.log 2>&1
1.5 说明与后续建议
-
压缩备份 :由于启用了 --compress,所以恢复时必须先解压再 prepare,再 copy-back。脚本里已经写了提醒,生产环境要严格遵循。
-
日志管理:日志文件会随着时间增长,虽然你加了清理逻辑,但建议定期归档或集中到日志服务器。
-
监控与告警:可以在脚本最后加一段邮件/钉钉/企业微信通知,把备份结果推送出去,避免只靠人工查看。
-
恢复演练 :建议定期做一次恢复演练,确认 --decompress → --prepare → --copy-back 全流程无误。
二. 配置增量备份
2.1 XtraBackup 8 增量备份的核心原理
1️⃣ 增量备份"增"的是什么?
👉 基于 LSN(Log Sequence Number)
-
全量备份:记录一个起始 LSN
-
增量备份:只备份 LSN 之后发生变化的 InnoDB 页
物理备份的本质是对比 LSN(Log Sequence Number,日志序列号)。
-
每个备份目录里都有一个文件叫 xtrabackup_checkpoints。
-
当你指定 --incremental-basedir 时,XtraBackup 会打开那个目录里的
xtrabackup_checkpoints,查看里面的 to_lsn。 -
本次备份就从这个 to_lsn 开始,拷贝之后所有变化的数据页。
LSN 信息存放在:xtrabackup_checkpoints文件。
bash
[root@localhost ~]# cat xtrabackup_checkpoints
backup_type = incremental
from_lsn = 323404380 #备份开始的 LSN(日志序列号);全量备份总是从 0 开始
to_lsn = 3640151788 #备份结束时记录的最后一个 LSN
last_lsn = 3640151788 #最后应用的 LSN,应该与 to_lsn相等,如果不相等,说明备份可能有问题
flushed_lsn = 3640151788 #已刷新到磁盘的 LSN
redo_memory = 0 #重做日志内存使用量(字节)
redo_frames = 0 #重做日志帧数
2️⃣增量备份的关键点是:
-
必须基于上一次的 全量备份 或 增量备份。
-
使用 --incremental-basedir 参数。
-
同样支持压缩、多线程、日志记录和旧备份清理。
-
恢复时:先
解压→ 再prepare→ 顺序不能错
3️⃣XtraBackup 的技术依据(为何必须这样做)
-
基于 LSN 的增量: XtraBackup 用
xtrabackup_checkpoints中的to_lsn/from_lsn标记范围。新的增量应当从"上一份备份的to_lsn"继续,否则链会断。 -
备份类型标识: 在
xtrabackup_checkpoints里有backup_type=Full|Incremental,这能验证目录是不是有效的备份集。 -
恢复顺序依赖: 恢复时需要先 prepare 全量,再按时间顺序依次应用每一份增量。如果基准选择错误,恢复阶段会失败或数据不一致。
2.2 增量备份命令
执行增量备份命令:
bash
[root@localhost ~]# xtrabackup --defaults-file=/etc/xtrabackup.cnf \
--backup \
--target-dir="${INC_BACKUP_DIR}" \
--incremental-basedir="${LATEST_BASE}" \
--parallel="${PARALLEL_THREADS}" \
--compress \
--compress-threads="${COMPRESS_THREADS}" \
--no-server-version-check \
>> "${LOG_FILE}" 2>&1
命令各参数详解:
| 参数 | 含义与作用 | 增量备份中的特殊意义 |
|---|---|---|
--defaults-file=/etc/xtrabackup.cnf |
指定包含数据库连接信息的配置文件路径(安全、规范)。 | 与全量备份相同。 |
--backup |
执行备份操作的主指令。 | 与全量备份相同,但结合 --incremental-basedir 后,其行为变为增量备份。 |
--target-dir="${INC_BACKUP_DIR}" |
指定本次增量备份文件的存储目录。 | 需要是一个新的、空的目录,用于存放增量数据。 |
--incremental-basedir="${LATEST_BASE}" |
【核心参数】 指定基准全量备份 的目录路径。XtraBackup会读取该目录下的 xtrabackup_checkpoints 文件,获取其结束时的LSN(日志序列号),然后只备份LSN大于该值的新数据页。 |
这是增量备份的灵魂 。LATEST_BASE 变量通常指向全量备份脚本创建的 latest_full 软链接(如/data/backup/physical_backup/latest_full),确保每次都基于最新的全备进行增量。 |
--parallel="${PARALLEL_THREADS}" |
设置并行拷贝线程数。 | 与全量备份相同。 |
--compress --compress-threads="..." |
启用并行压缩。 | 与全量备份相同。 |
--no-server-version-check |
跳过版本检查。 | 与全量备份相同。 |
>> "${LOG_FILE}" 2>&1 |
重定向所有输出到日志文件。 | 与全量备份相同。 |
2.3 编写增量备份脚本
增量备份优先基于增量备份,其次选择全量备份目录。
bash
[root@localhost ~]# vim xtrabackup_increment_backup.sh
#!/bin/bash
#
# ==============================================================================
# MySQL 增量物理备份脚本(基于 Percona XtraBackup 8)
# 适用于 MySQL 8.0 + 主从环境,优先在从库执行
# 作者:noleaf提供,生产可用
# 日期:2025-12-29
#===============================================================================
#设置xtrabackup和MySQL路径,脚本运行时会自动把 MySQL 和 XtraBackup 的路径加入 PATH
export PATH=/usr/local/mysql-8.0.44/bin:/usr/local/percona-xtrabackup-8.0.35/bin:/usr/bin:/bin
#更安全的错误处理
set -euo pipefail
#=============================变量定义==========================================
#定义时间戳
Timestamp=$(date '+%F_%H-%M-%S')
#备份根目录
BACKUP_BASE=/data/mysql/backup
#增量备份根目录
BACKUP_ROOT=${BACKUP_BASE}/physical_incremental_backup
#备份文件名称
BACKUP_NAME="inc_backup_${Timestamp}"
#增量备份目录
INC_BACKUP_DIR=${BACKUP_ROOT}/${BACKUP_NAME}
#日志目录及文件
LOG_DIR=${BACKUP_ROOT}/logs
LOG_FILE=${LOG_DIR}/${BACKUP_NAME}.log
#控制并行复制数据的线程数(自动计算20%CPU线程数,最小4)
PARALLEL_THREADS=$(($(nproc)*20/100))
[[ $PARALLEL_THREADS -lt 4 ]] && PARALLEL_THREADS=4
#控制并行压缩数据的线程数(自动计算10%CPU线程数,最小2)
COMPRESS_THREADS=$(($(nproc)*10/100))
[[ $COMPRESS_THREADS -lt 2 ]] && COMPRESS_THREADS=2
#定义清理文件时间
KEEP_DAYS=15
echo "==========================创建备份必要的目录======================="
mkdir -p "$BACKUP_ROOT" "$LOG_DIR" "$INC_BACKUP_DIR" || {
echo "ERROR: 无法创建备份相关目录"
exit 1
}
echo "========================== 增量备份开始于 [$Timestamp] ===================" | tee -a "$LOG_FILE"
#1.校验 xtrabackup 是否存在
command -v xtrabackup >/dev/null 2>&1 || {
echo "ERROR: xtrabackup 未安装" | tee -a "$LOG_FILE"
exit 1
}
#2.校验 MySQL 实例是否存活
if ! mysqladmin --defaults-extra-file=/etc/xtrabackup.cnf ping --silent; then
echo "ERROR: MySQL 实例不可用,取消备份" | tee -a "$LOG_FILE"
exit 1
fi
#=============================基准备份选择逻辑==================================
#选择哪个备份目录执行(全量备份或增量备份目录)
# 校验某个目录是否是有效的备份
is_valid_backup() {
local dir="$1"
local ck="${dir}/xtrabackup_checkpoints"
# 1. 检查文件是否存在
if [[ ! -f "$ck" ]]; then
return 1
fi
# 2. 检查内容是否包含有效关键字 (忽略大小写)
# XtraBackup 8.0 的关键字通常是 full-backuped 或 incremental
if grep -qE "full-backuped|incremental" "$ck"; then
return 0
else
return 1
fi
}
# 获取最新的增量和全量目录
LATEST_INC=$(ls -td ${BACKUP_ROOT}/inc_backup* 2>/dev/null | head -1 || true)
LATEST_FULL=$(ls -td ${BACKUP_BASE}/physical_full_backup/full_backup* 2>/dev/null | head -1 || true)
# 优先选择增量,否则选择全量
if [[ -n "$LATEST_INC" ]] && is_valid_backup "$LATEST_INC"; then
LATEST_BASE="$LATEST_INC"
elif [[ -n "$LATEST_FULL" ]] && is_valid_backup "$LATEST_FULL"; then
LATEST_BASE="$LATEST_FULL"
else
echo "ERROR: 未找到有效的基准备份(缺少 checkpoints 或类型不正确)。请先执行全量备份。" | tee -a "$LOG_FILE"
exit 1
fi
echo "基于备份目录: ${LATEST_BASE}" | tee -a "$LOG_FILE"
#=============================执行增量备份======================================
#4.执行增量备份
if xtrabackup --defaults-file=/etc/xtrabackup.cnf \
--backup \
--target-dir="${INC_BACKUP_DIR}" \
--incremental-basedir="${LATEST_BASE}" \
--parallel="${PARALLEL_THREADS}" \
--compress \
--compress-threads="${COMPRESS_THREADS}" \
--no-server-version-check \
>> "${LOG_FILE}" 2>&1; then
echo "Success: 增量备份成功!" | tee -a "$LOG_FILE"
else
echo "ERROR: 增量备份失败!请检查日志 ${LOG_FILE}" | tee -a "$LOG_FILE"
exit 1
fi
echo "Incremental backup completed at $(date '+%F_%H-%M-%S')" >> ${LOG_FILE}
#=============================清理15天之前的旧备份====================================
echo "正在清理 $KEEP_DAYS 天之前的旧增量备份..." | tee -a $LOG_FILE
find "${BACKUP_ROOT}" -maxdepth 1 -type d -name "inc_backup*" -mtime +${KEEP_DAYS} -exec rm -rf {} \;
find "${LOG_DIR}" -maxdepth 1 -type f -name "inc_backup*" -mtime +${KEEP_DAYS} -exec rm -f {} \;
#================================统计数据简报===========================================
BACKUP_SIZE=$(du -sh "${INC_BACKUP_DIR}" | cut -f1)
echo "本次增量备份大小:${BACKUP_SIZE}" | tee -a "$LOG_FILE"
echo "本次增量备份目录:${INC_BACKUP_DIR}" | tee -a "$LOG_FILE"
echo "=================== 增量备份完成于 [$(date '+%F %H:%M:%S')] ===================" | tee -a "$LOG_FILE"
2.4 加入计划任务
bash
[root@localhost ~]# crontab -e
# 每 4 小时一次增量,自动追溯有效基准
00 06,10,14,18,22 * * * /bin/bash /data/mysql/scripts/xtrabackup_incremental_backup.sh >> /var/log/xtrabackup_incremental_backup.log 2>&1
三. 数据恢复
前言:
物理恢复不是直接把备份目录考回 MySQL,必须经过以下三个核心阶段:
-
解压 (Decompress) : 因为备份时使用了
--compress,所有文件(.ibd)现在都是被压缩过的(后缀通常为.zst或.qp),MySQL 无法识别。必须先将它们还原成原始大小。 -
准备 (Prepare): 备份时,数据库是运行着的,数据包里可能包含"未提交的事务"或"已提交但未刷盘的 redo log"。
-
全量准备:回滚未提交事务,重做已提交事务,使数据达到一致性状态。
-
增量合并:将增量包里的"差异页"像补丁一样,按顺序一个个"贴"到全量备份上,最终拼成一个完整、最新的全量镜像。
-
-
回写 (Copy-back) : 将最终"准备好"的干净数据文件,拷贝回 MySQL 的
datadir。
3.1 恢复的原理
-
全量备份:包含某个时间点的完整数据文件(数据页 + redo 日志)。
-
增量备份:只保存自上一次备份以来发生变化的数据页(通过 LSN 范围识别)。
-
恢复过程:
-
先解压--decompress并prepare全量备份(应用 redo 日志,保证一致性)。
-
按顺序依次应用每一份增量备份(基于 LSN 的连续性)。
-
最后做一次 --apply-log --redo-only 或完整 --apply-log,让数据文件处于可启动状态。
-
将恢复好的数据目录替换 MySQL 的 datadir,启动实例。
-
3.2 恢复的详细步骤
当前目录结构大致是:
bash
[root@localhost ~]# tree -L 3 /data/mysql/backup/
/data/mysql/backup/
├── physical_full_backup/
│ └── full_backup_2025-12-29_02-00-01/
│ ├── ibdata1
│ ├── mysql.ibd
│ ├── xtrabackup_checkpoints
│ └── ...
└── physical_incremental_backup/
├── inc_backup_2025-12-29_04-00-01/
├── inc_backup_2025-12-29_06-00-01/
└── inc_backup_2025-12-29_08-00-01/
🌙 恢复的整体流程图
cpp
[全量备份]
↓ prepare --apply-log-only
[第1次增量]
↓ prepare --apply-log-only
[第2次增量]
↓ prepare --apply-log-only
...
[最后一次增量]
↓ prepare(不加 apply-log-only)
[一致性数据目录]
↓ copy-back
[MySQL datadir]
⚠️ 顺序错一次,数据就废
3.2.1 停止 MySQL 服务
恢复前必须停止服务,并清理原有的数据目录(重要:请先备份原数据目录,防止误操作)。
bash
[root@localhost ~]# systemctl stop mysql
[root@localhost ~]# mv /var/lib/mysql/data /var/lib/mysql/data_bak # 移走旧数据
[root@localhost ~]# mkdir -p /var/lib/mysql/data # 创建空目录
确认MySQL配置文件的datadir目录,下面所有 copy-back 都是往这里写
bash
[root@localhost ~]# grep datadir /etc/my.cnf
datadir=/var/lib/mysql/data
3.2.2 备份现有datadir(非常重要)
bash
[root@localhost ~]# mv /var/lib/mysql/data /var/lib/mysql/data.bak_$(date +%F_%H-%M)
[root@localhost ~]# mkdir -p /var/lib/mysql/data
[root@localhost ~]# chown -R mysql:mysql /var/lib/mysql/data
3.2.3 解压所有备份(如果使用了 --compress)
必须对全量和所有参与恢复的增量包执行解压。增量备份目录同样需要解压。
假设有两个增量备份:
-
inc_backup_2025-12-29_09-00-01 -
inc_backup_2025-12-29_16-00-01
bash
#解压全量备份目录
[root@localhost ~]# xtrabackup --decompress --target-dir=/data/mysql/backup/physical_full_backup/full_backup_2025-12-29_02-00-01
#解压每一个增量备份目录
[root@localhost ~]# xtrabackup --decompress --target-dir=/data/mysql/backup/physical_incremental_backup/inc_backup_2025-12-29_08-01-04
[root@localhost ~]# xtrabackup --decompress --target-dir=/data/mysql/backup/physical_incremental_backup/inc_backup_2025-12-29_16-00-01
⚠️ 解压后可以删除.zst 文件(节省空间),解压命令中建议带上 --remove-original
3.2.4 Prepare准备阶段
这是最关键、最易错的一步。必须在恢复的目标服务器上执行(不一定是原生产机)。
第一步:准备全量备份(基准备份)(必须加 --apply-log-only)
bash
# 使用 --apply-log-only 表示仅应用redo log,暂不完成最终恢复(为后续增量合并留出状态)
[root@localhost ~]# xtrabackup --prepare --apply-log-only --target-dir=/data/mysql/backup/physical_full_backup/full_backup_2025-12-29_02-00-01
第二步:合并第一个增量到全量
目前有两个增量备份:
-
inc_backup_2025-12-29_09-00-01 -
inc_backup_2025-12-29_16-00-01
① 合并第一个增量备份到基准备份
--incremental-dir 指定要合并的增量备份目录
bash
[root@localhost ~]# xtrabackup --prepare --apply-log-only \
--target-dir=/data/mysql/backup/physical_full_backup/full_backup_2025-12-29_02-00-01 \
--incremental-dir=/data/mysql/backup/physical_incremental_backup/inc_backup_2025-12-29_09-00-01
② 合并第二个增量备份(如果有更多增量,按时间顺序重复此步骤)
bash
[root@localhost ~]# xtrabackup --prepare --apply-log-only \
--target-dir=/data/mysql/backup/physical_full_backup/full_backup_2025-12-29_02-00-01 \
--incremental-dir=/data/mysql/backup/physical_incremental_backup/inc_backup_2025-12-29_16-00-01
第三步:执行最终的prepare(不再使用 --apply-log-only)
bash
# 此步骤会回滚未提交的事务,使数据文件达到一致状态,可以用于恢复。
[root@localhost ~]# xtrabackup --prepare --target-dir=/data/mysql/backup/physical_full_backup/full_backup_2025-12-29_02-00-01
准备阶段完成后,full_backup_2025-12-29_02-00-01目录中的数据就是一份完整且一致的数据快照,可以直接用于恢复了。
3.2.5 恢复阶段 (Copy-back)
此步骤会覆盖目标目录,操作前务必确认MySQL服务已停止且原数据已备份。
① 停止MySQL服务
bash
[root@localhost ~]# systemctl stop mysql
②【极端重要】备份原数据目录(可选但强烈建议)
bash
[root@localhost ~]# mv /var/lib/mysql/data var/lib/mysqsl/mysql-data_backup_$(date +%s)
③ 执行拷贝恢复
bash
# 使用 --copy-back 将准备好的数据复制到MySQL的数据目录,并且指定my.cnf文件
[root@localhost ~]# xtrabackup --defaults-file=/etc/my.cnf --copy-back --target-dir=/data/mysql/backup/physical_full_backup/full_backup_2025-12-29_02-00-01
④ 修正文件权限(MySQL进程需要对数据目录有读写权限)
bash
[root@localhost ~]# chown -R mysql:mysql /var/lib/mysql
⑤ 启动MySQL服务
bash
[root@localhost ~]# systemctl start mysql
⑥ 验证服务
sql
[root@localhost ~]# mysql -uroot -p
mysql> SHOW DATABASES;
mysql> USE your_database_name;
mysql> SELECT COUNT(*) FROM 核心表;
🎯 生产恢复流程 CheckList
-
确认备份链路完整(全量+增量时间顺序)
-
停止MySQL + 备份当前数据目录
-
解压所有备份文件
-
全量Prepare(--apply-log-only)
-
逐级增量Prepare(--apply-log-only)
-
最终Prepare(无参数)
-
权限修复 + 拷贝数据目录
-
启动MySQL + 验证数据