MySQL 5.7 全量 + 增量备份方案(本地执行 + 远程存储)
| 文档版本 | v1.0 |
|---|---|
| 适用版本 | MySQL 5.7.x + Percona XtraBackup 2.4 |
| 备份模式 | 物理热备(全量 + 增量) |
| 存储架构 | 本地临时备份 -> 推送远程备份服务器 |
| 维护人员 | 运维团队 |
一、方案概述
1.1 架构设计
本方案采用 本地执行备份 + 远程存储归档 的 Push 模式。
- 本地执行:备份脚本部署在 MySQL 数据库服务器,调用本地 XtraBackup 进行物理备份。
- 压缩传输 :备份时使用
--compress压缩,减少网络传输带宽。 - 远程存储 :备份完成后,通过
rsync over SSH推送到远程备份服务器。 - 本地清理:远程推送成功后,删除本地多余(除最近一次成功备份文件)备份文件,避免占用生产磁盘空间。
1.2 备份策略
| 备份类型 | 频率 | 执行时间 | 保留策略 (远程) | 本地保留 |
|---|---|---|---|---|
| 全量备份 | 每周 1 次 | 周日 17:00 | 180 天 | 最近一次成功备份 |
| 增量备份 | 每天 1 次 | 周一至周六 17:00 | 180 天 | 最近一次成功备份 |
1.3 目录规划
| 路径 | 说明 |
|---|---|
/usr/local/bin/mysql_backup_*.sh |
备份脚本 |
/data/backup/mysql/tmp/ |
本地临时备份目录 |
/data/backup/mysql/logs/ |
本地日志目录 |
backup-server:/data/remote_backup/mysql/ |
远程备份存储目录 |
二、环境准备
2.1 安装依赖
1) 所有 MySQL 节点
MySQL 5.7 必须使用 Percona XtraBackup 2.4 系列,且必须安装 qpress 以支持压缩。
bash
# 1. 安装 percona-release 配置工具
sudo yum install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
# 2. 启用 xtrabackup-24 仓库
sudo percona-release setup -y pxb-24
# 3. 安装 XtraBackup 2.4
sudo yum install -y percona-xtrabackup-24
# 4. 安装 qpress
sudo yum install qpress -y
# 5. 安装 rsync
sudo yum install -y rsync
# 6. 验证安装
xtrabackup --version
which qpress && qpress -V 2>/dev/null || echo "qpress: OK"
rsync --version | head -n1
或者离线安装
离线安装 percona-xtrabackup-24
2) 备份服务器安装
shell
# 5. 安装 rsync
sudo yum install -y rsync
2.2 创建 MySQL 备份账号
sql
CREATE USER 'user_backup'@'localhost' IDENTIFIED BY 'hjkk0*9TG1';
GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT, PROCESS ON *.* TO 'user_backup'@'localhost';
GRANT SELECT, SHOW VIEW, EVENT, TRIGGER ON *.* TO 'user_backup'@'localhost';
FLUSH PRIVILEGES;
-- 验证权限
SHOW GRANTS FOR 'user_backup'@'localhost';
2.3 配置 SSH 免密(推送到远程)
为了实现脚本自动推送,需配置 MySQL 服务器到备份服务器的 SSH 免密。
-
在 MySQL 服务器生成密钥:
bashssh-keygen -t rsa -
将公钥复制到备份服务器:
bashssh-copy-id <备份服务器 IP> -
验证免密:
bashssh root@<备份服务器 IP> -p 22 "echo success"
2.4 远程备份服务器准备
在备份服务器上创建接收目录并授权:
bash
mkdir -p /data/remote_backup/mysql/db_180
chmod 750 /data/remote_backup/mysql
2.5 修改文件描述符限制
shell
ulimit -n 63396
ulimit -u 31140
echo -e "* soft nofile 63396
* hard nofile 63396
* soft nproc 31140
* hard nproc 31140" >> /etc/security/limits.conf
三、备份脚本
3.1 公共配置模块 (/usr/local/bin/mysql_backup_config.sh)
将公共变量和函数提取,方便维护。
bash
#!/bin/bash
#===============================================================================
# 文件:mysql_backup_config.sh
# 描述:备份公共配置与函数库
#===============================================================================
# ------------------- 基础配置 -------------------
BACKUP_BASE_DIR="/data/backup/mysql"
TMP_DIR="${BACKUP_BASE_DIR}/tmp"
LOG_DIR="${BACKUP_BASE_DIR}/logs"
LOCK_FILE="/var/run/mysql_backup.lock"
# MySQL 连接信息
MYSQL_USER="user_backup"
MYSQL_PASS="hjkk0*9TG1"
MYSQL_HOST="localhost"
MYSQL_PORT="13306"
# 远程备份服务器配置
REMOTE_USER="root"
REMOTE_HOST="192.168.0.163" # 请修改为实际备份服务器 IP
REMOTE_SSH_PORT=22
REMOTE_DIR="/data/remote_backup/mysql/db_180" # 远程备份服务器目录请注意与其他库区分
# 备份参数
COMPRESS_THREADS=4
# ------------------- 函数库 -------------------
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
check_env() {
# 检查 qpress
if ! command -v qpress &> /dev/null; then
log "错误:未找到 qpress 命令,无法进行压缩备份"
exit 1
fi
# 检查 xtrabackup
if ! command -v xtrabackup &> /dev/null; then
log "错误:未找到 xtrabackup 命令"
exit 1
fi
# 创建目录
mkdir -p "${TMP_DIR}" "${LOG_DIR}"
}
acquire_lock() {
exec 200>"${LOCK_FILE}"
flock -n 200 || { log "另一个备份进程正在运行,退出"; exit 1; }
}
push_to_remote() {
local local_path=$1
local remote_subdir=$2
log "开始推送备份到远程服务器 ${REMOTE_HOST}..."
# 使用 rsync 推送
rsync -a --whole-file --partial \
-e "ssh -p ${REMOTE_SSH_PORT}" \
"${local_path}" \
"${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/${remote_subdir}/" \
>> "${LOG_FILE}" 2>&1
if [ $? -eq 0 ]; then
log "远程推送成功"
return 0
else
log "远程推送失败"
return 1
fi
}
clean_local() {
local path=$1
log "清理本地临时备份:${path}"
rm -rf "${path}"
}
3.2 全量备份脚本 (/usr/local/bin/mysql_backup_full.sh)
bash
#!/bin/bash
#===============================================================================
# 文件:mysql_backup_full.sh
# 描述:MySQL 全量备份脚本(周日执行)
#===============================================================================
source /usr/local/bin/mysql_backup_config.sh
LOG_FILE="${LOG_DIR}/full_$(date +%F).log"
BACKUP_DATE=$(date +%F_%H-%M-%S)
TARGET_DIR="${TMP_DIR}/full_${BACKUP_DATE}"
main() {
log "==================== 全量备份开始 ${TARGET_DIR} ===================="
check_env
acquire_lock
mkdir -p "${TARGET_DIR}"
# 1. 执行备份 (压缩)
log "执行 XtraBackup 全量备份..."
xtrabackup --user="${MYSQL_USER}" \
--password="${MYSQL_PASS}" \
--host="${MYSQL_HOST}" \
--port="${MYSQL_PORT}" \
--backup \
--target-dir="${TARGET_DIR}" \
--compress \
--compress-threads="${COMPRESS_THREADS}" \
2>> "${LOG_FILE}"
if [ $? -ne 0 ]; then
log "备份失败"
exit 1
fi
# 2. 推送到远程
if push_to_remote "${TARGET_DIR}" "full"; then
# 3. 清理本地旧备份 (保留最近一份用于下一次增量基准)
ls -td ${TMP_DIR}/full_* ${TMP_DIR}/incr_* 2>/dev/null | tail -n +2 | xargs rm -rf
log "全量备份完成"
else
log "推送失败,保留本地备份"
exit 1
fi
log "==================== 全量备份结束 ${TARGET_DIR} ===================="
}
main "$@"
3.3 增量备份脚本 (/usr/local/bin/mysql_backup_incr.sh)
bash
#!/bin/bash
#===============================================================================
# 文件:mysql_backup_incr.sh
# 描述:MySQL 增量备份脚本(周一至周六执行)
#===============================================================================
source /usr/local/bin/mysql_backup_config.sh
LOG_FILE="${LOG_DIR}/incr_$(date +%F).log"
BACKUP_DATE=$(date +%F_%H-%M-%S)
TARGET_DIR="${TMP_DIR}/incr_${BACKUP_DATE}"
# 获取上一次备份目录(全量或增量)
get_last_backup() {
# 为了支持增量,本地必须保留上一次备份(全量或增量),用于下一次增量的 basedir
# 查找本地 tmp 目录下最新的备份目录
local last_dir=$(ls -td ${TMP_DIR}/full_* ${TMP_DIR}/incr_* 2>/dev/null | head -n1)
echo "${last_dir}"
}
main() {
log "==================== 增量备份开始 ${TARGET_DIR} ===================="
check_env
acquire_lock
LAST_BACKUP_DIR=$(get_last_backup)
if [ -z "${LAST_BACKUP_DIR}" ]; then
log "错误:未找到基准备份目录,请先执行全量备份"
exit 1
fi
log "增量备份基准目录:${LAST_BACKUP_DIR}"
mkdir -p "${TARGET_DIR}"
# 1. 执行增量备份 (压缩)
log "执行 XtraBackup 增量备份..."
xtrabackup --user="${MYSQL_USER}" \
--password="${MYSQL_PASS}" \
--host="${MYSQL_HOST}" \
--port="${MYSQL_PORT}" \
--backup \
--target-dir="${TARGET_DIR}" \
--incremental-basedir="${LAST_BACKUP_DIR}" \
--compress \
--compress-threads="${COMPRESS_THREADS}" \
2>> "${LOG_FILE}"
if [ $? -ne 0 ]; then
log "增量备份失败"
exit 1
fi
# 2. 推送到远程
if push_to_remote "${TARGET_DIR}" "incr"; then
# 3. 清理本地旧备份 (保留最近一份用于下一次增量基准)
ls -td ${TMP_DIR}/full_* ${TMP_DIR}/incr_* 2>/dev/null | tail -n +2 | xargs rm -rf
log "增量备份完成"
else
log "推送失败,保留本地备份"
exit 1
fi
log "==================== 增量备份结束 ${TARGET_DIR} ===================="
}
main "$@"
⚠️ 增量备份特别说明 :
由于 XtraBackup 增量备份需要读取上一次备份的
xtrabackup_checkpoints文件,本地必须保留最近一次备份目录 。脚本中
clean_local逻辑已调整为:tail -n +2,即保留最近 1 份,删除更早的。这会导致本地始终占用约 1 份备份大小的空间。
3.4 授权脚本
shell
chmod +x /usr/local/bin/mysql_backup*
四、定时任务配置
创建日志目录:
shell
mkdir -p /data/backup/mysql/logs
编辑 crontab -e:
bash
# 全量备份 - 每周日 17:00
0 17 * * 0 /usr/local/bin/mysql_backup_full.sh >> /data/backup/mysql/logs/mysql_backup.log
# 增量备份 - 周一至周六 17:00
0 17 * * 1-6 /usr/local/bin/mysql_backup_incr.sh >> /data/backup/mysql/logs/mysql_backup.log
五、恢复流程(远程拉取)
当需要恢复时,从远程备份服务器拉取数据到目标机器。
5.1 准备环境
- 目标机器安装相同版本的 MySQL 5.7 和 XtraBackup 2.4。
- 停止 MySQL 服务。
- 清空数据目录。
5.2 拉取备份
bash
# 从备份服务器拉取全量和增量包到本地临时目录
mkdir -p /data/restore
rsync -avz backup_user@<备份服务器 IP>:/data/remote_backup/mysql/full/最新全量目录 /data/restore/
rsync -avz backup_user@<备份服务器 IP>:/data/remote_backup/mysql/incr/最新全量目录之后的所有增量目录 /data/restore/
5.3 解压与准备 (Prepare)
注意顺序:先解压,再 Prepare。
bash
# 1. 解压全量
xtrabackup --decompress --target-dir=/data/restore/最新全量目录 --remove-original
# 2. 解压第1个增量
xtrabackup --decompress --target-dir=/data/restore/第1个增量目录 --remove-original
# 依次解压2-n
# 3. 解压第n个增量
xtrabackup --decompress --target-dir=/data/restore/第n个增量目录 --remove-original
# 4. Prepare 全量
xtrabackup --prepare --apply-log-only --target-dir=/data/restore/最新全量目录
# 5. 合并第1个增量
xtrabackup --prepare --apply-log-only --target-dir=/data/restore/最新全量目录 \
--incremental-dir=/data/restore/第1个增量目录
# 依次合并2-n
# 6. 合并第n个增量
xtrabackup --prepare --target-dir=/data/restore/最新全量目录 \
--incremental-dir=/data/restore/第n个增量目录
5.4 恢复数据
bash
xtrabackup --copy-back --target-dir=/data/restore/最新全量目录
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqld
5.5 恢复后重建主从关系
查看 binlog 位置:
shell
cat ${最新全量目录}/xtrabackup_binlog_info
在从库执行:
sql
STOP SLAVE;
CHANGE MASTER TO
MASTER_HOST='192.168.0.165',
master_port=13306,
MASTER_USER='myslave',
MASTER_PASSWORD='sl@19kS0',
MASTER_LOG_FILE='mysql-bin.000123',
MASTER_LOG_POS=456789;
START SLAVE;
六、常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
qpress command not found |
未安装 qpress 或 PATH 错误 | yum install qpress 或配置 PATH |
rsync: connection unexpectedly closed |
SSH 密钥权限错误或网络不通 | 检查 ~/.ssh/backup_key 权限 (600),测试 SSH 连通性 |
增量备份失败 not found in checkpoints |
基准目录被删除或损坏 | 确保本地保留最近一份备份,不要手动清理 tmp 目录 |
| 本地磁盘爆满 | 推送失败导致本地文件未清理 | 检查推送日志,手动清理 /data/backup/mysql/tmp |
| 恢复后 MySQL 无法启动 | 权限错误 | 执行 chown -R mysql:mysql /var/lib/mysql |