XtraBackup 备份 Mysql 数据
下载安装
选择好对应版本
# 创建文件夹
mkdir -p /opt/xtrabackup/full
#将下好的tar包进行解压到/xtraBackup文件下
tar -xf Percona-XtraBackup-8.4.0-3-rcccec763-el8-x86_64-bundle.tar -C /opt/xtrabackup
# 安装
cd /opt/xtrabackup
yum install -y percona*
# 查看
xtrabackup -version
一、全量备份
备份
# 设置权限mysql GRANT权限
mysql -uroot -p use mysql;
update user set host='%' where user='root' ; GRANT BACKUP_ADMIN ON . TO 'root'@'%'
FLUSH PRIVILEGES;
# 备份 执行正确最后会显示 completed OK!
xtrabackup --backup \
--user=root \
--password='password' \
--target-dir=/opt/xtrabackup/full
恢复
#1、停止 MySQL 服务
systemctl stop mysqld
#2. 备份现有数据(可选但强烈建议)
mv /var/lib/mysql /var/lib/mysql_backup_$(date +%s)
mkdir /var/lib/mysql
chown mysql:mysql /var/lib/mysql
# 3恢复
#3.1. 准备全量备份
xtrabackup --prepare --target-dir=/opt/xtrabackup/full
#3.2 恢复
xtrabackup --copy-back --target-dir=/opt/xtrabackup/full
#3.3 权限
chown -R mysql:mysql /var/lib/mysql
chmod -R 750 /var/lib/mysql
#3.4 启动
systemctl start mysqld
二、增量备份
增量备份第一次
# 创建第一次增量备份目录
mkdir -p /opt/xtrabackup/incremental_backup_1_20250618
# 执行第一次增量备份
xtrabackup --user=root --password='password' --backup --target-dir=/opt/xtrabackup/incremental_backup_1_20250618 --incremental-basedir=/opt/xtrabackup/full
# 对第一次增量备份进行prepare
xtrabackup --prepare --target-dir=/opt/xtrabackup/incremental_backup_1_20250618
增量备份第二次
# 创建第二次增量备份目录
mkdir -p /opt/xtrabackup/incremental_backup_2_20250618
# 执行第二次增量备份
xtrabackup --user=root --password='password' --backup --target-dir=/opt/xtrabackup/incremental_backup_2_20250618 --incremental-basedir=/opt/xtrabackup/incremental_backup_1_20250618
# 对第二次增量备份进行prepare
xtrabackup --prepare --target-dir=/opt/xtrabackup/incremental_backup_2_20250618
合并增量备份到全量备份
# 对全量备份进行初步prepare,允许后续添加增量
xtrabackup --prepare --apply-log-only --target-dir=/opt/xtrabackup/full
# 首先将第一次增量合并到全量备份
xtrabackup --prepare --target-dir=/opt/xtrabackup/full --incremental-dir=/opt/xtrabackup/incremental_backup_1_20250618
# 然后将第二次增量合并到全量备份
xtrabackup --prepare --target-dir=/opt/xtrabackup/full --incremental-dir=/opt/xtrabackup/incremental_backup_2_20250618
# 执行最终的prepare,不使用--apply-log-only参数
xtrabackup --prepare --target-dir=/opt/xtrabackup/full
数据恢复
#1、停止 MySQL 服务
systemctl stop mysqld
#2. 备份现有数据(可选但强烈建议)
mv /var/lib/mysql /var/lib/mysql_backup_$(date +%s)
mkdir /var/lib/mysql
chown mysql:mysql /var/lib/mysql
# 3恢复
#3.1. 准备全量备份
xtrabackup --prepare --target-dir=/opt/xtrabackup/full
#3.2 恢复
xtrabackup --copy-back --target-dir=/opt/xtrabackup/full
#3.3 权限
chown -R mysql:mysql /var/lib/mysql
chmod -R 750 /var/lib/mysql
#3.4 启动
systemctl start mysqld
三、备份恢复脚本
数据备份
主要功能:每月全量备份数据到文件夹,之后再增量备份,如果找不到全量备份则先全量备份,之后压缩上传服务器(结合定时任务做到每日备份一次)
#!/bin/bash # XtraBackup级联增量备份脚本 # 功能:每月1号执行全量备份,其余时间执行基于前一个备份的增量备份 # 自动识别最后一次备份路径,支持全量+级联增量的备份策略 # 备份文件包含日期和时分秒,便于识别 # 备份文件全部放到年月命名的文件夹下,如:202506 # 传输到远程服务器后删除压缩包,保留原始备份 # 配置信息 USER="root" # MySQL用户名 PASSWORD="123456" # MySQL密码 BACKUP_DIR="/opt/xtrabackup" # 本地备份目录 REMOTE_SERVER="192.168.10.55" # 远程服务器IP REMOTE_DIR="/opt/xtrabackup/53apfuture" # 远程备份目录 REMOTE_USER="root" # 远程服务器用户名 # 日志文件 LOG_FILE="/opt/xtrabackup/xtrabackup.log" # 获取当前日期和时间 DATE=$(date +%Y%m%d) DATETIME=$(date +%Y%m%d_%H%M%S) YEAR_MONTH=$(date +%Y%m) # 日志函数 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE } # 错误处理函数 handle_error() { log "ERROR: $1" echo "错误: $1" >&2 exit 1 } # 检查命令执行状态 check_status() { if [ $? -ne 0 ]; then handle_error "$1" else log "$2" fi } # 创建年月目录(如果不存在) create_month_dir() { local month_dir="$BACKUP_DIR/$YEAR_MONTH" if [ ! -d "$month_dir" ]; then log "创建年月目录: $month_dir" mkdir -p "$month_dir" check_status "创建年月目录失败" "创建年月目录成功" fi # 检查目录权限 if [ ! -w "$month_dir" ]; then log "修改目录权限: $month_dir" chmod 755 "$month_dir" check_status "修改目录权限失败" "修改目录权限成功" fi } # 查找最近一次备份(可以是全量或增量) find_last_backup() { # 先创建年月目录 create_month_dir # 查找最近的备份目录(全量或增量) local latest_backup=$(ls -td $BACKUP_DIR/$YEAR_MONTH/xtrabackup_{full,add}_* 2>/dev/null | grep -v '\.tar\.gz' | head -1) if [ -n "$latest_backup" ]; then log "找到最近的备份: $latest_backup" echo "$latest_backup" return 0 else log "未找到任何备份,将执行全量备份" return 1 fi } # 全量备份函数 full_backup() { # 先创建年月目录 create_month_dir local backup_name="xtrabackup_full_$DATETIME" local backup_path="$BACKUP_DIR/$YEAR_MONTH/$backup_name" local tar_name="xtrabackup_full_$DATETIME.tar.gz" local tar_path="$BACKUP_DIR/$YEAR_MONTH/$tar_name" log "开始全量备份: $backup_path" # 检查并清理目标目录 if [ -d "$backup_path" ]; then log "清理已有备份目录: $backup_path" rm -rf "$backup_path" fi # 执行全量备份 xtrabackup --user=$USER --password=$PASSWORD --backup --target-dir=$backup_path check_status "全量备份失败" "全量备份成功" # 创建压缩包 log "创建压缩包: $tar_path" tar -zcf $tar_path -C $BACKUP_DIR/$YEAR_MONTH $backup_name check_status "创建压缩包失败" "创建压缩包成功" # 传输到远程服务器 log "开始传输到远程服务器: $REMOTE_SERVER:$REMOTE_DIR" scp $tar_path $REMOTE_USER@$REMOTE_SERVER:$REMOTE_DIR/ check_status "传输到远程服务器失败" "传输到远程服务器成功" # 传输成功后,删除本地压缩包,保留原始备份目录 log "删除本地压缩包: $tar_path" rm -f $tar_path } # 增量备份函数(基于前一个备份) incremental_backup() { # 先创建年月目录 create_month_dir local last_backup=$(find_last_backup) if [ $? -ne 0 ]; then log "未找到可基于的备份,执行全量备份" full_backup return fi local backup_name="xtrabackup_add_$DATETIME" local backup_path="$BACKUP_DIR/$YEAR_MONTH/$backup_name" local base_dir=$(basename $last_backup) local tar_name="xtrabackup_add_$DATETIME.tar.gz" local tar_path="$BACKUP_DIR/$YEAR_MONTH/$tar_name" log "开始增量备份: $backup_path (基于 $base_dir)" # 检查并清理目标目录 if [ -d "$backup_path" ]; then log "清理已有备份目录: $backup_path" rm -rf "$backup_path" fi # 执行增量备份(基于前一个备份) xtrabackup --user=$USER --password=$PASSWORD --backup --target-dir=$backup_path \ --incremental-basedir=$last_backup check_status "增量备份失败" "增量备份成功" # 验证增量备份的LSN连续性 local inc_from_lsn=$(grep "from_lsn" "$backup_path/xtrabackup_checkpoints" | awk '{print $3}') local last_to_lsn=$(grep "to_lsn" "$last_backup/xtrabackup_checkpoints" | awk '{print $3}') if [ "$inc_from_lsn" != "$last_to_lsn" ]; then handle_error "增量备份LSN不连续: from_lsn=$inc_from_lsn vs 前一个to_lsn=$last_to_lsn" fi # 创建压缩包 log "创建压缩包: $tar_path" tar -zcf $tar_path -C $BACKUP_DIR/$YEAR_MONTH $backup_name check_status "创建压缩包失败" "创建压缩包成功" # 传输到远程服务器 log "开始传输到远程服务器: $REMOTE_SERVER:$REMOTE_DIR" scp $tar_path $REMOTE_USER@$REMOTE_SERVER:$REMOTE_DIR/ check_status "传输到远程服务器失败" "传输到远程服务器成功" # 传输成功后,删除本地压缩包,保留原始备份目录 log "删除本地压缩包: $tar_path" rm -f $tar_path } # 主程序 log "==========================================" log "开始备份脚本执行" # 检查是否为每月1号或无可用备份 if [ $(date +%d) -eq 1 ] || [ -z "$(find_last_backup 2>/dev/null)" ]; then log "今天是每月1号 或 无可用备份,执行全量备份" full_backup else log "执行增量备份(基于前一个备份)" incremental_backup fi log "备份脚本执行完成" log "=========================================="
数据恢复
注意,数据库版本 和 XtraBackup 需要一致
# Backup恢复脚本(修复LSN匹配问题) # 功能:正确准备备份并处理增量合并,添加LSN验证 # 配置信息 USER="root" PASSWORD="123456" BACKUP_DIR="/opt/xtrabackup/test" MYSQL_DATA_DIR="/var/lib/mysql" MYSQL_SERVICE="mysqld" EXTRACT_DIR="$BACKUP_DIR/extract" # 日志文件 LOG_FILE="/opt/xtrabackup/restore.log" # 日志函数 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE } # 错误处理函数 handle_error() { log "ERROR: $1" echo "错误: $1" >&2 exit 1 } # 检查命令执行状态 check_status() { if [ $? -ne 0 ]; then handle_error "$1" else log "$2" fi } # 解压所有备份文件 extract_all_backups() { log "开始解压所有备份文件" mkdir -p "$EXTRACT_DIR" local all_backups=$(ls -t $BACKUP_DIR/*.tar.gz 2>/dev/null) if [ -z "$all_backups" ]; then handle_error "未找到备份压缩包" fi log "找到备份压缩包: $all_backups" for tar_file in $all_backups; do local backup_name=$(basename ${tar_file%.tar.gz}) local extract_dir="$EXTRACT_DIR/$backup_name" mkdir -p "$extract_dir" tar -zxf "$tar_file" -C "$extract_dir" --strip-components=1 check_status "解压 $tar_file 失败" "解压 $tar_file 成功" done log "解压完成" } # 查找备份并排序 find_sorted_backups() { log "查找并排序备份" local full_backups=$(ls -td $EXTRACT_DIR/xtrabackup_full_* 2>/dev/null) if [ -z "$full_backups" ]; then handle_error "未找到全量备份" fi local latest_full=$(echo $full_backups | awk '{print $1}') log "最新全量备份: $latest_full" # 提取完整备份的日期部分(如 20250619) local base_date=$(basename "$latest_full" | cut -d'_' -f3 | cut -c1-8) # 按时间戳排序增量备份(从旧到新) local inc_backups=$(ls -t -d $EXTRACT_DIR/xtrabackup_add_${base_date}_* 2>/dev/null | sort) log "找到增量备份: $inc_backups" export LATEST_FULL="$latest_full" export INCREMENTAL_BACKUPS="$inc_backups" } # 准备备份函数关键部分 prepare_backups() { log "开始准备备份" log "准备全量备份(带--apply-log-only)" xtrabackup --prepare --apply-log-only --target-dir=$LATEST_FULL check_status "全量备份准备失败" "全量备份准备成功" # 获取全量备份的to_lsn local full_to_lsn=$(grep "to_lsn" "$LATEST_FULL/xtrabackup_checkpoints" | awk '{print $3}') log "全量备份 to_lsn: $full_to_lsn" if [ -n "$INCREMENTAL_BACKUPS" ]; then local inc_list=($INCREMENTAL_BACKUPS) local last_idx=$(( ${#inc_list[@]} - 1 )) log "开始合并增量备份(共 ${#inc_list[@]} 个)" for i in "${!inc_list[@]}"; do local inc_backup=${inc_list[$i]} local is_last=$((i == last_idx)) # 验证增量备份完整性 log "验证增量备份 $inc_backup" if [ ! -f "$inc_backup/xtrabackup_checkpoints" ]; then handle_error "增量备份 $inc_backup 缺少 xtrabackup_checkpoints 文件" fi # 获取增量备份的from_lsn local inc_from_lsn=$(grep "from_lsn" "$inc_backup/xtrabackup_checkpoints" | awk '{print $3}') log "增量备份 $inc_backup from_lsn: $inc_from_lsn" # 检查LSN匹配 if [ "$inc_from_lsn" != "$full_to_lsn" ]; then handle_error "LSN不匹配: 全量备份to_lsn=$full_to_lsn vs 增量from_lsn=$inc_from_lsn" fi log "增量备份 $inc_backup 验证通过" # 合并增量备份(显式指定--apply-log参数) if $is_last; then log "合并最后一个增量备份(终极准备,--apply-log=0)" xtrabackup --prepare --apply-log=0 --target-dir=$LATEST_FULL --incremental-dir=$inc_backup else log "合并增量备份(应用日志,--apply-log-only)" xtrabackup --prepare --apply-log-only --target-dir=$LATEST_FULL --incremental-dir=$inc_backup fi check_status "合并增量备份 $inc_backup 失败" "合并增量备份 $inc_backup 成功" # 更新全量备份的to_lsn为当前增量的to_lsn full_to_lsn=$(grep "to_lsn" "$LATEST_FULL/xtrabackup_checkpoints" | awk '{print $3}') log "更新后全量备份 to_lsn: $full_to_lsn" done log "增量合并完成" else log "无增量备份需要合并" fi # 最终检查备份状态 local check_file="$LATEST_FULL/xtrabackup_checkpoints" if [ -f "$check_file" ]; then # 同时检查backup_type和LSN一致性 local backup_type=$(grep "backup_type" "$check_file" | awk '{print $3}') local last_lsn=$(grep "last_lsn" "$check_file" | awk '{print $3}') local to_lsn=$(grep "to_lsn" "$check_file" | awk '{print $3}') if [ "$backup_type" = "full-prepared" ] && [ "$last_lsn" = "$to_lsn" ]; then log "备份准备完成,状态正常 (backup_type=$backup_type, lsn=$last_lsn)" else log "检测到备份状态异常: backup_type=$backup_type, last_lsn=$last_lsn, to_lsn=$to_lsn" log "尝试执行终极准备命令以修复状态..." # 尝试执行终极准备命令 xtrabackup --prepare --target-dir=$LATEST_FULL if [ $? -ne 0 ]; then handle_error "终极准备命令执行失败,无法修复备份状态" fi # 再次检查状态 backup_type=$(grep "backup_type" "$check_file" | awk '{print $3}') if [ "$backup_type" = "full-prepared" ]; then log "状态修复成功: backup_type=$backup_type" else handle_error "终极准备命令执行后状态仍未修复,backup_type=$backup_type" fi fi else handle_error "检查点文件不存在" fi } # 恢复数据 restore_data() { log "开始恢复数据" systemctl stop $MYSQL_SERVICE check_status "停止MySQL失败" "停止MySQL成功" rm -rf $MYSQL_DATA_DIR/* check_status "清理数据目录失败" "清理数据目录成功" log "复制备份数据到MySQL" xtrabackup --copy-back --target-dir=$LATEST_FULL check_status "复制数据失败" "复制数据成功" chown -R mysql:mysql $MYSQL_DATA_DIR chmod -R 755 $MYSQL_DATA_DIR check_status "设置权限失败" "设置权限成功" systemctl start $MYSQL_SERVICE check_status "启动MySQL失败" "启动MySQL成功" log "数据恢复完成" } # 主程序 log "==========================================" log "开始恢复流程" extract_all_backups find_sorted_backups prepare_backups restore_data log "恢复完成" log "=========================================="

浙公网安备 33010602011771号