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 + 验证数据

相关推荐
sim202016 小时前
systemctl isolate graphical.target命令不能随便敲
linux·mysql
lkbhua莱克瓦2417 小时前
进阶-索引3-性能分析
开发语言·数据库·笔记·mysql·索引·性能分析
IT教程资源C19 小时前
(N-089)基于springboot网上订餐系统
mysql·springboot订餐系统
IT教程资源D19 小时前
[N_083]基于springboot毕业设计管理系统
mysql·springboot毕业设计
韦东东19 小时前
DeepSeek:R1本地RAG 问答: 功能新增,附 六大关键技术优化路径参考
数据库·mysql
赵渝强老师20 小时前
【赵渝强老师】MySQL的数据约束
数据库·mysql
半部论语20 小时前
MySQL 主机被封问题详解:原因、解除方法与预防策略
数据库·mysql
高溪流21 小时前
1.MySql概念讲解 及 MySql安装教程
数据库·mysql
IT教程资源D1 天前
[N_089]基于springboot网上订餐系统
mysql·springboot订餐系统
数据库知识分享者小北1 天前
免费体验《自建 MySQL 迁移至 PolarDB 分布式 V2.0》
数据库·分布式·mysql·阿里云·云原生·polardb