MySQL 5.7 全量 + 增量备份方案(本地执行 + 远程存储)

MySQL 5.7 全量 + 增量备份方案(本地执行 + 远程存储)

文档版本 v1.0
适用版本 MySQL 5.7.x + Percona XtraBackup 2.4
备份模式 物理热备(全量 + 增量)
存储架构 本地临时备份 -> 推送远程备份服务器
维护人员 运维团队

一、方案概述

1.1 架构设计

本方案采用 本地执行备份 + 远程存储归档 的 Push 模式。

  1. 本地执行:备份脚本部署在 MySQL 数据库服务器,调用本地 XtraBackup 进行物理备份。
  2. 压缩传输 :备份时使用 --compress 压缩,减少网络传输带宽。
  3. 远程存储 :备份完成后,通过 rsync over SSH 推送到远程备份服务器。
  4. 本地清理:远程推送成功后,删除本地多余(除最近一次成功备份文件)备份文件,避免占用生产磁盘空间。

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 免密。

  1. 在 MySQL 服务器生成密钥

    bash 复制代码
    ssh-keygen -t rsa
  2. 将公钥复制到备份服务器

    bash 复制代码
    ssh-copy-id <备份服务器 IP>
  3. 验证免密

    bash 复制代码
    ssh 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 准备环境

  1. 目标机器安装相同版本的 MySQL 5.7 和 XtraBackup 2.4。
  2. 停止 MySQL 服务。
  3. 清空数据目录。

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
相关推荐
猿小喵1 小时前
MySQL数据库源码调试
数据库·mysql
WangJunXiang62 小时前
Mysql数据库操作
数据库·mysql·oracle
2401_858936882 小时前
51 单片机入门踩坑实录:从编译报错到数码管显示 1234 的完整解决
数据库
java1234_小锋2 小时前
Java高频面试题:Spring框架中的单例bean是线程安全的吗?
java·数据库·spring
代码探秘者2 小时前
【大模型应用】5.深入理解向量数据库
java·数据库·后端·python·spring·面试
2401_832035342 小时前
使用Python处理计算机图形学(PIL/Pillow)
jvm·数据库·python
roman_日积跬步-终至千里2 小时前
【论文ing】强化学习重塑 NL2SQL:单轮对齐、多轮交互与细粒度评估的最新进展(2020–2026)
数据库·sql·microsoft
杨超越luckly2 小时前
AI Agent应用指南 :自动化构建品牌数据库:提示词 + API + 结构化输出
大数据·数据库·人工智能·自动化·ai agent
写代码的小阿帆2 小时前
MySQL多表联查——内连、外连
数据库·mysql