MySQL数据库备份之xtrabackup

10/16/2022 MySQL

是基于MySQL的服务器的开源热备份实用程序,在备份期间不会锁定数据库。支持的InnoDB,XtraDB和MyISAM表引擎。

# 简介

提示:可以结合rsync将备份文件复制到远程服务器上实现灾备,再使用mysqlbinlog工具同步binlog到远程服务器上以备份增量数据

Percona XtraBackup (opens new window)是基于MySQL的服务器的开源热备份实用程序,在备份期间不会锁定数据库。支持的InnoDB,XtraDB和MyISAM表引擎。

版本选择:

  • xtrabackup2.4支持(推荐):MySQL 5.1,5.5,5.6和5.7
  • xtrabackup8.0支持:MySQL8.0.0,MySQL8.0.20及以后的版本不支持

# 安装

yum install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
percona-release enable-only tools release
yum install -y percona-xtrabackup-24 qpress

# 全量备份与恢复

# 创建备份所使用的用户

CREATE USER 'backupuser'@'localhost' IDENTIFIED BY 'PASSWORD';
GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO 'backupuser'@'localhost';
FLUSH PRIVILEGES;

# 全量备份

参数说明:

--backup 参数指定为备份的操作
--target-dir=xxx 目录必须不存在或者为空,否则会备份失败
--compress 压缩备份
--databases='mysql sys information_schema performance_schema test' 指定备份的数据库,MySQL自带的库一定要写上,否则恢复后无法启动
--databases-exclude="db1 db2" 指定不备份的库
--tables-exclude="db.table1 db.table2" 指定不备份的表

执行备份:

mkdir -p /data/backups/
xtrabackup --user=backupuser --password="PASSWORD" --backup --target-dir=/data/backups/

# 全量恢复

注意事项:

  1. 一般情况下为了不影响线上业务,会使用新的MySQL实例进行恢复,然后导出误删的数据进行恢复。
  2. 如果备份时压缩过,则需要先解压缩,然后再执行恢复的步骤,解压缩:
    xtrabackup --decompress --target-dir=/data/backups/
    

恢复步骤: 1、恢复前停止MySQL服务,MySQL的datadir目录必须为空。

systemctl stop mysqld
mv /var/lib/mysql /var/lib/mysqlbackup
  1. 准备恢复,检查是否可恢复,检查中途不能中断 --prepare参数指定为检查恢复的操作
xtrabackup --user=backupuser --password="PASSWORD" --prepare --target-dir=/data/backups
  1. 执行恢复,准备恢复无误后操作
--copy-back参数指定为恢复的操作
xtrabackup --user=backupuser --password="PASSWORD" --copy-back --target-dir=/data/backups

也可以使用文件复制的方式

rsync -avrP /data/backups/ /var/lib/mysql/
  1. 恢复完成后修正所属者
chown -R mysql:mysql /var/lib/mysql
  1. 启动MySQL
systemctl start mysqld

# 增量备份与恢复

注意事项:

  1. 先全量备份,再增量备份,例如每周一次全量备份,基于全量备份每天做一次增量备份,或者每天一次全量备份,每小时一次增量备份。
  2. 增量备份可以基于全量备份,也可以基于上次增量备份,根据磁盘容量和数据量大小来选择。
  3. 恢复的时候先执行准备恢复,将增量数据合并到全量数据上,最后执行全量数据恢复,需要注意的是最后一次增量恢复准备时不用加参数:--apply-only-log

# 备份

mkdir -p /data/backups
#全量备份
xtrabackup --user=backupuser --password="PASSWORD" --backup --target-dir=/data/backups/base

#增量备份一
xtrabackup --user=backupuser --password="PASSWORD" --backup --target-dir=/data/backups/inc1 --incremental-basedir=/data/backups/base

#增量备份二,基于增量备份一
xtrabackup --user=backupuser --password="PASSWORD" --backup --target-dir=/data/backups/inc2 --incremental-basedir=/data/backups/inc1

# 恢复

# 恢复准备

--apply-only-log 来防止回滚阶段

systemctl stop mysqld
mv /var/lib/mysql /var/lib/mysqlbackup

#恢复准备全量备份
xtrabackup --user=backupuser --password="PASSWORD" --prepare --apply-log-only --target-dir=/data/backups/base

#恢复准备增量备份一,这时会将增量备份数据合并到全量备份中
xtrabackup --user=backupuser --password="PASSWORD" --prepare --apply-log-only --target-dir=/data/backups/base --incremental-dir=/data/backups/inc1

#恢复准备增量备份二,这时会将增量备份数据合并到全量备份中
xtrabackup --user=backupuser --password="PASSWORD" --prepare --target-dir=/data/backups/base --incremental-dir=/data/backups/inc2

# 执行恢复

xtrabackup --user=backupuser --password="PASSWORD" --copy-back --target-dir=/data/backups/base
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqld

# MySQL binlog基于时间点恢复

xtrabackup备份数据后会记录MySQL的binlog日志的文件名称和position信息到xtrabackup_binlog_info文件中(需开启MySQL的binlog)

开启binlog vim /etc/my.cnf

[mysqld]
log_bin=mysql-bin
server-id=1
expire_logs_days=30

根据binlog基于时间点恢复数据 注意事项:恢复前关闭binlog日志

mysql -uroot -proot -e 'set sql_log_bin=0'
MASTER_LOG_POS=`head -n 1 /data/backups/xtrabackup_binlog_info|cut -f2`
MASTER_LOG_FILE=`head -n 1 /data/backups/xtrabackup_binlog_info|cut -f1`
mysqlbinlog --start-position=$MASTER_LOG_POS --stop-datetime="2022-07-05 14:13:00" /var/lib/mysql/$MASTER_LOG_FILE > data.sql
mysql -uroot -proot < data.sql
mysql -uroot -proot -e 'set sql_log_bin=1'

# 备份脚本

方案一:每天01:00一次全量备份,7点至23点每一小时增量备份,保留最近30天的备份

echo "0 1,7-23 * * * root /usr/local/scripts/xtrabackup.sh --user=backupuser --password=PASSWORD" >> /etc/crontab

方案二:每周一01:00一次全量备份,每天01:00增量备份,保留最近30天的备份

echo "0 1 * * * root /usr/local/scripts/xtrabackup.sh --backup-full-dirname=`date +%Y-%U` --backup-inc-dirname=`date +%u-%Y%m%d` --user=backupuser --password=PASSWORD" >> /etc/crontab
mkdir /usr/local/scripts
vim /usr/local/scripts/xtrabackup.sh
chmod a+x /usr/local/scripts/xtrabackup.sh
##!/bin/bash

BACKUP_DIR=/data/backups
BACKUP_DAYS=30
BACKUP_COMPRESS=1
BACKUP_FULL_DIRNAME=`date +%Y-%m-%d`
BACKUP_INC_DIRNAME=`date +%H-%Y%m%d`
MYSQL_USER="root"
MYSQL_PASSWORD="root"
MYSQL_PORT=3306

get_help() {
	echo '用法:'
	echo 'xtrabackup.sh [options]...'
	echo 'options:'
	echo '  --backup-dir=/data/backups             备份保存的路径'
	echo '  --backup-days=30                       备份保留几天'
	echo '  --compress=1                           是否压缩备份'
	echo '  --backup-full-dirname=`date +%Y-%m-%d` 全量备份目录名称,可用于控制全量备份周期,如每天:date +%Y-%m-%d,每周:date +%Y-%U'
	echo '  --backup-inc-dirname=`date +%H-%Y%m%d` 增量备份目录名称,可用于控制增量备份周期,如每天:%H-%Y%m%d,每周:date +%u-%Y%m%d'
	echo '  --user=root                            MySQL用户'
	echo '  --password=root                        MySQL密码'
	echo '  --port=3306                            MySQL端口'
}

ARGS=`getopt -o h --long help,backup-dir:,backup-days:,compress:,backup-full-dirname:,backup-inc-dirname:,user:,password:,port: -n "$0" -- "$@"`
if [ $? != 0 ]; then
    echo "Terminating..."
    exit 1
fi
#echo ARGS=[$ARGS]
eval set -- "${ARGS}"
while true
do
	case "$1" in
		-h|--help)
			get_help
			shift
			exit 0
			;;
		--backup-dir)
			BACKUP_DIR=$2
			shift 2
			;;
		--backup-days)
			BACKUP_DAYS=$2
			shift 2
			;;
		--compress)
			BACKUP_COMPRESS=$2
			shift 2
			;;
		--backup-full-dirname)
			BACKUP_FULL_DIRNAME=$2
			shift 2
			;;
		--backup-inc-dirname)
			BACKUP_INC_DIRNAME=$2
			shift 2
			;;
		--user)
			MYSQL_USER=$2
			shift 2
			;;
		--password)
			MYSQL_PASSWORD=$2
			shift 2
			;;
		--port)
			MYSQL_PORT=$2
			shift 2
			;;
		--)
            shift
            break
            ;;
        *)
            echo "Internal error!"
            exit 1
            ;;
    esac
done

XTRABACKUP=/usr/bin/xtrabackup
BACKUP_DIR_TERM=$BACKUP_DIR/$BACKUP_FULL_DIRNAME
BACKUP_FULL_DIR=$BACKUP_DIR_TERM/full
BACKUP_INC_DIR=$BACKUP_DIR_TERM/$BACKUP_INC_DIRNAME
LOGFILE=$BACKUP_DIR/backup.log
XTRALOGFILE=$BACKUP_DIR/xtrabackup.log

backup_run() {
	backup_init
	backup_database
	backup_clean
}

backup_init() {
	if [ ! -f $XTRABACKUP ];then
		echo "$XTRABACKUP 不存在"
		exit 1
	fi
    if [ ! -d $BACKUP_DIR_TERM ];then
        mkdir -p $BACKUP_DIR_TERM
    fi
}

backup_clean() {
	if [ "$BACKUP_DIR" != "/" ];then
		find $BACKUP_DIR -type d -mtime +$BACKUP_DAYS -exec rm {} \; > /dev/null 2>&1
    fi
}

save_log() {
	echo $1;
    echo "[`date +'%Y-%m-%d %H:%M:%S'`] $1" >> $LOGFILE
}

backup_database() {
    COMMAND="$XTRABACKUP --user=$MYSQL_USER --password=$MYSQL_PASSWORD --port=$MYSQL_PORT --backup"
    NEWEST_DIRNAME=`ls -t $BACKUP_DIR_TERM | head -n 1`
    if [ "$NEWEST_DIRNAME" = "" ];then
		COMMAND="$COMMAND --target-dir=$BACKUP_FULL_DIR"
    else
		BASEDIR=$BACKUP_DIR_TERM/$NEWEST_DIRNAME
		COMMAND="$COMMAND --target-dir=$BACKUP_INC_DIR --incremental-basedir=$BASEDIR"
    fi
    if [ $BACKUP_COMPRESS -eq 1 ];then
		COMMAND="$COMMAND --compress"
    fi

    save_log "beging backup:$COMMAND"
    $($COMMAND >> $XTRALOGFILE 2>&1)
    if [ $? -eq 0 ];then
        save_log "backup successful"
    else
        save_log "backup failure"
    fi
}

backup_run

🕑 最后更新时间: 2022-10-16 15:05