企业级 MySQL 8.0 物理备份实践:使用 XtraBackup 实现全量与增量自动备份
1. 为什么选择 XtraBackup?
- 热备份:备份期间不影响数据库的读写。
- 物理备份:直接拷贝数据文件,恢复速度极快。
- 增量备份:仅备份自上次以来发生变化的数据块,节省空间。
2. 安装过程中的"深坑"
在 CentOS 7 上安装,最常见的问题是依赖项找不到或官方源下载过慢。
第一步:安装 Percona 源
bash
sudo yum install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
第二步:配置 ps80 库
bash
sudo percona-release setup ps80
第三步:解决依赖(重点)
qpress 压缩工具不在 Percona 源里,必须先装 EPEL。如果下载慢,建议换成阿里源或清华源:
bash
sudo yum install -y epel-release
sudo yum install -y percona-xtrabackup-80 qpress
3. 核心备份脚本:db_backup.sh
这个脚本集成了三个高级功能:
- 智能连接:Socket 找不到时自动切 TCP/IP。
- 重名处理 :同日多次运行自动加
_1,_2后缀。 - 链式增量:永远基于"上一次成功备份"进行增量。
bash
#!/bin/bash
# ========================================================
# MySQL 全自动物理备份脚本 (XtraBackup 8.0)
# ========================================================
# --- 基础配置 ---
USER="bkpuser"
PASSWORD="bkpuser@2026"
SOCKET="/tmp/mysql.sock" # 宝塔等面板常在 /tmp/ 下
HOST="127.0.0.1" # 备用连接地址
DATADIR="/www/server/data" # 数据库实际存储路径
BACKUP_BASE="/data/backup" # 备份存放总目录
# --- 自动处理时间与目录 ---
DATE=$(date +%F)
DAY_OF_WEEK=$(date +%u) # 1-7 (7为周日)
LOG_FILE="$BACKUP_BASE/backup.log"
mkdir -p "$BACKUP_BASE/full" "$BACKUP_BASE/inc"
exec >> "$LOG_FILE" 2>&1
echo "==================== 备份开始: $(date '+%Y-%m-%d %H:%M:%S') ===================="
# 1. 智能连接策略
if [ -S "$SOCKET" ]; then
CONN_OPTS="--socket=$SOCKET"
else
echo "[Warning] Socket文件不存在,尝试通过HOST连接..."
CONN_OPTS="--host=$HOST --port=3306"
fi
# 2. 目录冲突函数:如果目录存在,则重命名为 _1, _2...
get_safe_dir() {
local b_dir=$1; local b_name=$2; local target="$b_dir/$b_name"
local count=1
while [ -d "$target" ]; do
target="${b_dir}/${b_name}_${count}"
((count++))
done
echo "$target"
}
# 3. 确定备份基准
LAST_SUCCESS=$(ls -td $BACKUP_BASE/full/* $BACKUP_BASE/inc/* 2>/dev/null | head -1)
# 4. 执行备份逻辑
if [ "$DAY_OF_WEEK" -eq 7 ] || [ -z "$LAST_SUCCESS" ]; then
# 【全量备份】条件:周日 或 没有任何备份记录
T_DIR=$(get_safe_dir "$BACKUP_BASE/full" "${DATE}_full")
echo "[Info] 执行全量备份 -> $T_DIR"
xtrabackup --backup $CONN_OPTS --user=$USER --password=$PASSWORD --datadir=$DATADIR --target-dir=$T_DIR --no-server-version-check
else
# 【增量备份】条件:周一至周六 且 存在基准
T_DIR=$(get_safe_dir "$BACKUP_BASE/inc" "${DATE}_inc")
echo "[Info] 执行增量备份 -> $T_DIR (基准: $LAST_SUCCESS)"
xtrabackup --backup $CONN_OPTS --user=$USER --password=$PASSWORD --datadir=$DATADIR --target-dir=$T_DIR --incremental-basedir=$LAST_SUCCESS --no-server-version-check
fi
# 5. 结果校验
if [ $? -eq 0 ]; then
echo "[Success] 备份已完成。"
else
echo "[Error] 备份进程异常退出!"
[ -d "$T_DIR" ] && rm -rf "$T_DIR" # 清理残余空目录
exit 1
fi
# 6. 自动清理 (保留近30天的备份)
# find $BACKUP_BASE -mtime +30 -type d -exec rm -rf {} \;
echo "==================== 备份结束: $(date '+%Y-%m-%d %H:%M:%S') ===================="
4. 如何在灾难发生时进行恢复?
增量备份的恢复像"接龙"一样,必须按顺序准备。
步骤 A:整理全量(Prepare)
这一步是把未提交的事务回滚,应用日志。
bash
xtrabackup --prepare --apply-log-only --target-dir=/data/backup/full/2026-01-04_full
步骤 B:合并所有增量
按照时间顺序,依次将增量包合并进全量包。最后一个包不需要加 --apply-log-only。
bash
# 合并周一增量
xtrabackup --prepare --apply-log-only --target-dir=/data/backup/full/2026-01-04_full --incremental-dir=/data/backup/inc/2026-01-05_inc
# ... 如果还有周二、周三,以此类推 ...
步骤 C:恢复到数据目录
停止 MySQL 并清理旧数据(注意先做原始数据的移动备份!):
bash
systemctl stop mysqld
mv /www/server/data /www/server/data_old
mkdir /www/server/data
xtrabackup --copy-back --target-dir=/data/backup/full/2026-01-04_full
chown -R mysql:mysql /www/server/data
systemctl start mysqld
5. 日常维护建议
- 权限 :确保执行脚本的用户对
/data/backup有写权限。 - 空间 :物理备份占用空间大,建议开启
find命令清理 30 天前的备份。 - 验证:备份成功不代表能恢复,建议每季度拉取一个增量包到测试机做恢复演练。