XtraBackup是由知名数据库软件服务企业Percona提供的一款热备工具,除了能够支持最为常见的MyISAM、InnoDB引擎对象,还支持XtraDB引擎(一款由PerconaTeam在InnoDB基础之上开发的,目标就是要取代InnoDB存储引擎)。Percona官网中介绍XtraBackup是世界上唯一一款开源、免费、备份时读写无阻塞、支持增量、专用于InnoDB、XtraDB的热备工具等,看着让人非常动心,官方还总结了使用 XtraBackup的下面几个优点:
备份集高效、完整、可用。
备份任务执行过程中不会阻塞事务
节省磁盘空间,降低网络带宽占用。
备份集自动验证机制。
恢复更快。
xtrabackup下载地址,大家按需下载对应的版本。
一、全库还原
备份逻辑:
a. 数据库运行期间,拷贝数据表空间.
b. 拷贝的同时,会将备份期间的redo进行备份
恢复逻辑 :
模拟了InnoDB Crash Recovery 功能,需要要将备份进行处理(前滚和回滚)后才能恢复
1、rpm -ivh percona-xtrabackup-80-8.0.27-19.1.el7.x86_64.rpm --force --nodeps
2、全量备份
mkdir -p /data/backup/full
xtrabackup --defaults-file=/etc/my.cnf --user=root --password="123123" --port=3306 --backup --target-dir=/data/backup/full --socket=/tmp/mysql.sock
数据恢复
[root@db01 ~]# pkill mysqld
[root@db01 ~]# rm -rf /data/3306/data/*
[root@db01 ~]# rm -rf /data/3306/logs/*
[root@db01 ~]# rm -rf /data/3306/binlog/*
3、准备:(CR)
xtrabackup --prepare --target-dir=/data/backup/full
说明:模拟CR过程,将redo前滚,undo回滚,让备份数据是一致状态
4 拷回数据:
xtrabackup --copy-back --target-dir=/data/backup/full
5、修改权限并启动数据库
[root@db01 data]# chown -R mysql.mysql /data/*
[root@db01 data]# /etc/init.d/mysqld start
以上是全库的一个测试。
二、drop/delete/truncate误删数据后的恢复
1、开始全备
xtrabackup --defaults-file=/etc/my.cnf --user=root --password=123123 --innodb_data_home_dir=/data/mysql/ --innodb_log_group_home_dir=/data/mysql/ --parallel=4 --socket=/tmp/mysql.sock --target-dir=/backup/base --backup 2> /backup/backup.log
说明:
--target-dir 备份数据目录
--parallel 指定备份时拷贝多个数据文件并发的进程数,默认值为1
2、预检查
xtrabackup --prepare --target-dir=/backup/base/
3、备份恢复
xtrabackup --copy-back --target-dir=/backup/base/
4、开始日志恢复
cd base/
cat xtrabackup_binlog_info
mysqlbinlog --start-position=3291 /data/mysql/mysql-bin.000002
mysqlbinlog --start-position=3291 /data/mysql/mysql-bin.000002|grep -i sqlroad
mysqlbinlog --start-position=3291 --stop-position=5028 /data/mysql/mysql-bin.000002 >/opt/incbinlog.sql
mysql -uroot -proot -e"set sql_log_bin=0;"
mysql -uroot -proot -e"source /opt/incbinlog.sql;"
三、物理备份脚本
#!/bin/bash
#################################################
#Version : v1.0.0
#Author : zhouhuanhuan
#Time : 2023-07-19
#Auto HotBackup For MySQL #
#################################################
#autohotbackup tools
#备份根目录
BackupRoot=/backup
#全量备份根目录
FullBackupRoot=${BackupRoot}/full
#增量备份根目录
IncrementalBackupRoot=${BackupRoot}/incre
#xtrabackup 备份时log
Log=/data/log/autohotbackup_$(date +%Y-%m-%d).log
#现在星期几
Week=$(date +%w)
Hour=$(date +%H)
#全量备份时间,按照星期定义,周一到周日依次1,2,3,4,5,6,7
FullBackupWeek=(1 2 3 4 5)
#是否开启binlog备份,ON / OFF
BinlogBackup=ON
#全量备份时间,
#例子, 周一 10-11 点响应 ,周二 15-16 点
FullBackupTime=(1:10 2:15)
FullBackupTime=(1:04 2:04 3:04 4:04 5:04 6:04 0:04)
#增量备份时间,小时
IncrementalBackupIntervalTime=2
#过期时间,超过这个时间将删除,天
DeadLine=4
#MySQL信息
readonly MysqlAddress="localhost"
readonly MysqlPort="3306"
readonly MysqlUser="root"
readonly MysqlPassword="123123"
readonly MysqlSocket=/tmp/mysql.sock
readonly MysqlConfigFile=/etc/my.cnf
#Innobackupex
#使用内存
readonly UseMemory=1000M
#Innobackupex
#其他选项
readonly InnobackupexConfigure="--backup"
#SCP,传输已备份文件到备份服务器
#readonly BackupServerAddress=192.168.10.105
#readonly BackupServerPort=22
#readonly BackupServerUser=root
#readonly BackupServerDir=/backup
#模块开关
#备份文件到另一台服务器,ON/on代表打开,OFF/off代表关闭
#readonly IncrementalBackup=ON
#readonly TarZip=ON
#readonly ScpFile=ON
#readonly BinlogBackup=OFF
#readonly DeleteFile=ON
#pigz 多线程压缩工具是否启用,可能会消耗更多的CPU资源
#readonly UsePigz=YES
#bin Path
readonly INNOBACKUPEX=$(which xtrabackup 2>/dev/null || echo "xtrabackup")
readonly MYSQLADMIN=$(which mysqladmin 2>/dev/null || echo "mysqladmin")
readonly MYSQL=$(which mysql 2>/dev/null || echo "mysql")
readonly MKDIR=$(which mkdir 2>/dev/null || echo "mkdir")
readonly FIND=$(which find 2>/dev/null || echo "find")
readonly TAR=$(which tar 2>/dev/null || echo "tar")
readonly SCP=$(which scp 2>/dev/null || echo "scp")
readonly PIGZ=$(which pigz 2>/dev/null || echo "pigz")
echo "*************** $(date +%c): Xtrabackup 进行MySQL热备份 ***************"
echo " "
#主函数
function Main_Fun() {
echo " "
echo "*************** $(date +%c): Xtrabackup 进行MySQL热备份 ***************"
echo ""
Delete_File
Backup_Policy
Tar_Gzip
Scp_File
#Delete_File
}
#判断mysql可以连接
function Mysql_Alive() {
local TestConnectMySQL=$(mysqladmin -h"${MysqlAddress}" -P"${MysqlPort}" -u"${MysqlUser}" -p"${MysqlPassword}" ping 2>/dev/null | grep -c alive)
if [ "${TestConnectMySQL}" = 1 ];then
echo "连接 MySQL($MysqlAddress) 成功,开始备份 !"
else
echo "连接 MySQL($MysqlAddress) 失败,退出"
exit 1
fi
}
#全量备份
function Full_Backup() {
#判断备份目录是否存在
echo "*** 进行全量备份 ***"
[ -d ${FullBackupRoot} ] || ${MKDIR} ${FullBackupRoot} -p
#[ $? == 0 ] || echo "创建 ${BackupRoot} 失败,退出! " ; exit 1
if [ $? != 0 ];then
echo "创建 ${FullBackupRoot} 失败,退出! "
exit 1
fi
#判断mysql可活可连接
Mysql_Alive
#进行备份命令
${INNOBACKUPEX} --user="${MysqlUser}" --password="${MysqlPassword}" "${InnobackupexConfigure}" --target-dir="${FullBackupRoot}" --socket="${MysqlSocket}"
#进行判断
[ $? == 0 ] && echo "全量备份成功" || echo "全量备份失败!"
BackupType="FULL"
}
#基于全量进行增量备份
function Base_Full_Backup() {
if [ "${IncrementalBackup}" == "ON" -o "${IncrementalBackup}" == "on" ];then
echo "*** 尝试基于全量增量备份 "
elif [ "${IncrementalBackup}" == "OFF" -o "${IncrementalBackup}" == "off" ];then
echo " 增量备份开关已关闭 "
return
else
echo "增量备份开关配置错误,错误配置 IncrementalBackup= ${IncrementalBackup} ! "
return
fi
#echo " 尝试基于全量增量备份 ***"
#获取上次全量备份目录名,根据全名查找,如果找不到,则破例进行全量备份
local LatestFullBackup=$(${FIND} ${FullBackupRoot} -mindepth 1 -maxdepth 1 -type d -printf "%P\n" 2>/dev/null | sort -nr | head -1)
if [ ! "${LatestFullBackup}" ];then
echo "在 ${FullBackupRoot} 下面没有找到全量备份,将进行全量备份 !"
sleep 2
#Full_Backup
return
#exit
fi
local LatestFullBackupRoot=${FullBackupRoot}/${LatestFullBackup}
local IncrementalBasedirRoot=${LatestFullBackupRoot}
#判断mysql可活可连接
#Mysql_Alive
echo "本次(基于全量)--incremental-basedir= ${IncrementalBasedirRoot}"
echo " "
sleep 3
#判断增量备份目录是否存在
[ -d ${IncrementalBackupRoot} ] || ${MKDIR} ${IncrementalBackupRoot} -p
#判断mysql可活可连接
#Mysql_Alive
#进行备份操作
${INNOBACKUPEX} --defaults-file="${MysqlConfigFile}" --use-memory="${UseMemory}" --host="${MysqlAddress}" --user="${MysqlUser}" --password="${MysqlPassword}" "${InnobackupexConfigure}" --incremental --incremental-basedir="${IncrementalBasedirRoot}" ${IncrementalBackupRoot}
#判断是否成功备份
[ $? == 0 ] && echo "基于 ${IncrementalBasedirRoot} 全量的增量备份成功 " || echo "基于 ${IncrementalBasedirRoot} 全量的增量备份失败!"
BackupType="INCREMENTAL"
}
#基于增量进行增量备份
function Base_Incremental_Backup() {
if [ "${IncrementalBackup}" == "ON" -o "${IncrementalBackup}" == "on" ];then
echo "*** 尝试基于全量增量备份 "
elif [ "${IncrementalBackup}" == "OFF" -o "${IncrementalBackup}" == "off" ];then
echo " 增量备份开关已关闭 "
return
else
echo "增量备份开关配置错误,错误配置 IncrementalBackup= ${IncrementalBackup} ! "
return
fi
#echo " 尝试基于增量的增量备份 ***"
local LatestIncrementalBackup=$(${FIND} ${IncrementalBackupRoot} -mindepth 1 -maxdepth 1 -type d -printf "%P\n" 2>/dev/null | sort -nr | head -1)
if [ ! "$LatestIncrementalBackup" ];then
echo "在 ${IncrementalBackupRoot} 没找到增量备份,将运行基于全量备份模块 !"
sleep 2
#Base_Full_Backup
return
#exit
fi
local LatestIncrementalBackupRoot=${IncrementalBackupRoot}/${LatestIncrementalBackup}
local IncrementalBasedirRoot=${LatestIncrementalBackupRoot}
#判断mysql可活可连接
#Mysql_Alive
echo "本次(基于增量)--incremental-basedir= ${IncrementalBasedirRoot} "
echo " "
sleep 3
#开始操作备份
${INNOBACKUPEX} --defaults-file="${MysqlConfigFile}" --use-memory="${UseMemory}" --host="${MysqlAddress}" --user="${MysqlUser}" --password="${MysqlPassword}" "${InnobackupexConfigure}" --incremental --incremental-basedir="${IncrementalBasedirRoot}" ${IncrementalBackupRoot}
#判断是否成功备份
[ $? == 0 ] && echo "基于 ${IncrementalBasedirRoot} 增量的增量备份成功 " || echo "基于 ${IncrementalBasedirRoot} 增量的增量备份失败!"
BackupType="INCREMENTAL"
}
#打包加压模块,主要进行整理文件
function Tar_Gzip() {
#echo ${BackupType}
[ ! "${BackupType}" ] && return
#判断是否打开打包加压开关
if [ "${TarZip}" == "ON" -o "${TarZip}" == "on" ];then
echo "******************* 进行打包加压操作 ***********************"
elif [ "${TarZip}" == "OFF" -o "${TarZip}" == "off" ];then
echo "打包加压开关为 off 状态 !"
return
else
echo "打包加压开关配置错误,错误配置 TarZip= ${TarZip} !"
return
fi
#echo " "
#echo "进行打包加压操作 !"
sleep 3
if [ "${BackupType}" == "FULL" ];then
local LatestFullBackup=$(${FIND} ${FullBackupRoot} -mindepth 1 -maxdepth 1 -type d -printf "%P\n" 2>/dev/null | sort -nr | head -1)
echo " "
cd "${FullBackupRoot}"
# 判断是否启用pigz工具多线程压缩,默认不启用
if [ "${UsePigz}" == "YES" -o "${UsePigz}" == "yes" ];then
echo "使用 ${PIGZ} 进行多线程压缩 ${LatestFullBackup}"
${TAR} -icvf - ${LatestFullBackup} --remove-file | ${PIGZ} > "${LatestFullBackup}".tar.gz
else
${TAR} -izcf "${LatestFullBackup}".tar.gz "${LatestFullBackup}" --remove-file
fi
[ $? == 0 ] && echo "在 ${FullBackupRoot} 下面已对 ${LatestFullBackup} 打包加压成 ${LatestFullBackup}.tar.gz !"
TarZipFile=${FullBackupRoot}/${LatestFullBackup}.tar.gz
elif [ "${BackupType}" == "INCREMENTAL" ];then
local LatestIncrementalBackup=$(${FIND} ${IncrementalBackupRoot} -mindepth 1 -maxdepth 1 -type d -printf "%P\n" 2>/dev/null | sort -nr | head -1)
echo " "
cd "${IncrementalBackupRoot}"
# 判断是否启用pigz工具多线程压缩,默认不启用
if [ "${UsePigz}" == "YES" -o "${UsePigz}" == "yes" ];then
echo "使用 ${PIGZ} 进行多线程压缩 ${LatestFullBackup}"
${TAR} -icvf - ${LatestIncrementalBackup} --remove-file | ${PIGZ} > "${LatestIncrementalBackup}".tar.gz
else
${TAR} -izcf "${LatestIncrementalBackup}".tar.gz "${LatestIncrementalBackup}" --remove-file
fi
[ $? == 0 ] && echo "在 ${IncrementalBackupRoot} 下面已对 ${LatestIncrementalBackup} 打包加压成 ${LatestIncrementalBackup}.tar.gz !"
TarZipFile=${IncrementalBackupRoot}/${LatestIncrementalBackup}.tar.gz
fi
}
#时间控制,主要进行控制备份策略
function Backup_Policy() {
local NOW=$(date +%c)
echo "******************************* ${NOW} *****************************"
#FullBackupTime
for BackupTime in ${FullBackupTime[]}
do
#echo ${BackupTime}
FullBackupWeek=${BackupTime%%:}
if [ "${FullBackupWeek}" == "${Week}" ];then
#判断是否全量备份
local FullBackupHour=${BackupTime##:}
if [ "${FullBackupHour}" == "${Hour}" ];then
echo " 进行全量备份 "
sleep 3
#Full_Backup
return
fi
#判断需不需要基于全量备份
local HourNow=$((IncrementalBackupIntervalTime + FullBackupHour))
if [ "${Hour}" == "${HourNow}" ];then
#进行基于全量的增量备份
echo " 尝试基于全量增量备份 ***"
sleep 3
#Base_Full_Backup
return
fi
fi
done
#判断需不需要基于全量备份
#HourNow=$((IncrementalBackupIntervalTime + FullBackupHour))
echo "*** 尝试基于增量的增量备份 ***"
sleep 3
#Base_Incremental_Backup
return
}
#进行同步备份文件,只是同步已经打包加压成 .tar.gz 的文件
function Scp_File() {
#间接获取是否执行innobackupex
[ ! "${BackupType}" ] && return
#判断打包压缩模块是否打开,打开备份模块才生效
[ "${TarZip}" == "ON" -o "${TarZip}" == "on" ] || return
#判断是否打开备份开关
if [ "${ScpFile}" == "ON" -o "${ScpFile}" == "on" ];then
echo "******************* 将使用SCP命令传输备份数据库文件 ***********************"
elif [ "${ScpFile}" == "OFF" -o "${ScpFile}" == "off" ];then
echo " "
echo "备份状态为 off,没进行传备份文件 ${TarZipFile} 到服务器 ${BackupServerAddress} !"
return
else
echo " "
echo "备份配置错误,错误配置 ScpFile= ${ScpFile}"
return
fi
#echo "******************* 将使用SCP命令传输备份数据库文件 ***********************"
${SCP} -P "${BackupServerPort}" "${TarZipFile}" "${BackupServerUser}"@${BackupServerAddress}:${BackupServerDir}
#判断是成功备份
[ "$?" == "0" ] && echo "备份文件 ${TarZipFile} 到服务器 ${BackupServerAddress} 的 ${BackupServerDir} 成功 !" || echo "备份文件 ${TarZipFile} 到服务器失败 !"
}
#删除备份文件,删除备份策略
function Delete_File() {
echo ""
if [ "${DeleteFile}" == "ON" -o "${DeleteFile}" == "on" ];then
echo "*** 查询并删除过期文件 ***"
elif [ "${DeleteFile}" == "OFF" -o "${DeleteFile}" == "off" ];then
echo "删除文件状态为关闭 !"
return
else
echo "删除模块配置错误,错误配置 DeleteFile=${DeleteFile} "
return
fi
#整理全量备份的目录
echo "*** 查询全量备份目录 ${FullBackupRoot} ***"
local FindResult=$(${FIND} ${FullBackupRoot}/*.tar.gz -type f -mtime +${DeadLine} 2>/dev/null)
if [ "${FindResult}" ];then
echo "将在目录 ${FullBackupRoot} 删除一下文件: "
echo "${FindResult}"
#进行删除文件
sleep 5
${FIND} ${FullBackupRoot}/*.tar.gz -type f -mtime +${DeadLine} -exec rm -rf {} \;
else
echo "在目录 ${FullBackupRoot} 下面没有可删除过期( ${DeadLine} 天)文件 !"
fi
#整理增量备份的目录
echo "*** 查询增量备份目录 ${IncrementalBackupRoot} ***"
local FindResult=$(${FIND} ${IncrementalBackupRoot}/*.tar.gz -type f -mtime +${DeadLine} 2>/dev/null)
if [ "${FindResult}" ];then
echo "将在目录 ${IncrementalBackupRoot} 删除一下文件: "
echo "${FindResult}"
#进行删除文件
${FIND} ${IncrementalBackupRoot}/*.tar.gz -type f -mtime +${DeadLine} -exec rm -rf {} \;
sleep 5
${FIND} ${IncrementalBackupRoot}/*.tar.gz -type f -mtime +${DeadLine} -exec rm -rf {} \;
else
echo "在目录 ${IncrementalBackupRoot} 下面没有可删除过期( ${DeadLine} 天)文件 !"
fi
}
#Backup_Policy
Main_Fun >> ${Log} 2>&1
#Base_Incremental_Backup
#Base_Full_Backup
#Incremental_Backup
#Full_Backup