Xtrabackup8配置MySQL8全量备份及增量备份

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 的工作流如下:

  1. 连接 :根据 --defaults-file 登录 MySQL。

  2. 拷贝 :开启多个线程 (--parallel) 同时读取数据文件。

  3. 处理 :读取的数据交给压缩线程 (--compress-threads) 进行实时压缩。

  4. 持久化 :将处理后的数据写入目标目录 (--target-dir)。

  5. 收尾 :记录当前的 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,必须经过以下三个核心阶段:

  1. 解压 (Decompress) : 因为备份时使用了 --compress,所有文件(.ibd)现在都是被压缩过的(后缀通常为 .zst.qp),MySQL 无法识别。必须先将它们还原成原始大小。

  2. 准备 (Prepare): 备份时,数据库是运行着的,数据包里可能包含"未提交的事务"或"已提交但未刷盘的 redo log"。

    • 全量准备:回滚未提交事务,重做已提交事务,使数据达到一致性状态。

    • 增量合并:将增量包里的"差异页"像补丁一样,按顺序一个个"贴"到全量备份上,最终拼成一个完整、最新的全量镜像。

  3. 回写 (Copy-back) : 将最终"准备好"的干净数据文件,拷贝回 MySQL 的 datadir

3.1 恢复的原理

  • 全量备份:包含某个时间点的完整数据文件(数据页 + redo 日志)。

  • 增量备份:只保存自上一次备份以来发生变化的数据页(通过 LSN 范围识别)。

  • 恢复过程

    1. 先解压--decompress并prepare全量备份(应用 redo 日志,保证一致性)。

    2. 按顺序依次应用每一份增量备份(基于 LSN 的连续性)。

    3. 最后做一次 --apply-log --redo-only 或完整 --apply-log,让数据文件处于可启动状态。

    4. 将恢复好的数据目录替换 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

  1. 确认备份链路完整(全量+增量时间顺序)

  2. 停止MySQL + 备份当前数据目录

  3. 解压所有备份文件

  4. 全量Prepare(--apply-log-only)

  5. 逐级增量Prepare(--apply-log-only)

  6. 最终Prepare(无参数)

  7. 权限修复 + 拷贝数据目录

  8. 启动MySQL + 验证数据

相关推荐
Bdygsl1 分钟前
MySQL(1)—— 基本概念和操作
数据库·mysql
身如柳絮随风扬10 分钟前
什么是左匹配规则?
数据库·sql·mysql
jiankeljx33 分钟前
mysql之如何获知版本
数据库·mysql
小李来了!1 小时前
数据库DDL、DML、DQL、DCL详解
数据库·mysql
我科绝伦(Huanhuan Zhou)2 小时前
【生产案例】MySQL InnoDB 数据损坏崩溃修复
数据库·mysql·adb
海棠蚀omo3 小时前
从零敲开 MySQL 的大门:库与表的基础操作实战(保姆级入门指南)
数据库·mysql
廋到被风吹走3 小时前
【MySql】超时问题分析
java·数据库·mysql
y = xⁿ3 小时前
重生之我创作出了小红书:对象存储模块,用户资料模块
后端·mysql·intellij-idea
Y001112363 小时前
Day10-MySQL-事物
数据库·sql·mysql
轩情吖3 小时前
MySQL之用户管理
数据库·c++·后端·mysql·权限管理·用户管理