mysql增量备份一般是使用binlog来实现,但是效果和实现方法远没有其他商用数据库优秀,找了很久,决定用Xtrabackup结合脚本的方式实现全备和增量备份,本着不重复造轮子的原则,网上找到了一些现成的脚本,自己再把代码做了一些优化,加了一些功能,脚本适用于指定库的备份和指定时间段恢复(考虑到单库恢复后的可用性,默认将mysql和performance_schema两个库一起进行了备份),也可修改脚本内容实现全库备份,脚本如下:

全备

使用方法:

./full_bak.sh "database1 database2 database3"
cat full_bak.sh
#!/bin/sh
# mysql全量备份脚本

mysql_conf_file=/etc/my.cnf
backup_dir=/home/mysql_bak/
host=127.0.0.1
port=3306
user=root
passwd=xxxx

#每天在备份目录对应数据库下面生成一个文件夹
run_full_bak(){
database=$1
today_dir=${backup_dir}/${database}/$(date +%Y%m%d)
if [ ! -d $today_dir ];
then
        mkdir -p $today_dir
else
        echo "$today_dir exists, it will be cleaned before full-backup"
        rm -rf ${today_dir}/*
        echo "$today_dir clean success"
fi

innobackupex \
        --host=$host --port=$port \
        --user=$user --password=$passwd \
        --databases="$database mysql performance_schema" $today_dir
echo ">_< successfully full-backup to $today_dir"
}
dbs="$1"
for db in $dbs;
do
        run_full_bak "$db"
done

增量备份

使用方法:

./inc_bak.sh "database1 database2 database3"
cat inc_bak.sh
#!/bin/sh
# mysql增量备份脚本

backup_dir=/home/mysql_bak
host=127.0.0.1
port=3306
user=root
passwd=xxxx

run_inc_bak(){
database=$1
sub_dir=$(ls -lh ${backup_dir}/${database} | awk '{word=$9}END{print word}')
recent_dir=${backup_dir}/${database}/$sub_dir

sub_dir=$(ls -lh $recent_dir | awk '{word=$9}END{print word}')
base_dir=${recent_dir}/$sub_dir

if [ ${#sub_dir} -eq 0 ]; then
        echo "!-- please do full-backup before incre-backup"
        exit
fi

innobackupex \
        --incremental-basedir=$base_dir \
        --incremental $recent_dir \
        --host=$host --port=$port \
        --user=$user --password=$passwd \
        --databases="$database mysql performance_schema"
echo ">_< successfully incre-backup to $recent_dir"
}
dbs="$1"
for db in $dbs;
do
        run_inc_bak "$db"
done

还原

使用方法:
可指定时间恢复

./restore.sh /backup/20191212 2019-12-12_15-16-07
#!/bin/sh
cat restore.sh
# mysql恢复脚本,可指定时间恢复

mysql_data_dir=/home/mysql
mysql_before_restore_path=/home/mysql_bak
restore_buffer_size=512M

if [ ! -d ${mysql_data_dir} ];
then
        mkdir -p ${mysql_data_dir}
else
        rm -fr ${mysql_data_dir}/*
fi

restore_dir=$1
restore_time=$2
if [ ${#restore_dir} -eq 0 ]; then
        echo "[Error] You must give the restore_dir and restore_time, such as ./restore.sh /backup/20191212 2019-12-12_15-16-07"
        exit
fi

# 打印设置项
echo "Your settings are :"
echo "mysql_data_dir       : $mysql_data_dir"
echo "mysql_before_restore : $mysql_before_restore_path"
echo "restore_buffer_size  : $restore_buffer_size"
echo "restore_dir          : $restore_dir"
echo "restore_time         : $restore_time"

# 获取备份个数(全量+增量)
num=$(ls -lh $restore_dir |grep -B100 "$restore_time"| awk 'BEGIN{i=-1}{i+=1}END{print i}')
base_dir=${restore_dir}/$(ls -lh $restore_dir |grep -B100 "$restore_time"| awk 'BEGIN{i=0}{if(i==1){a=$9} i+=1}END{print a}')
i=0
ls -lh $restore_dir|grep -B100 "$restore_time" | while read line
do
        sub_dir=$(echo $line | awk '{word=$9}END{print word}')
        cur_dir=${restore_dir}/$sub_dir
        if [ $i -eq 0 ]; then
                :
        elif [ $i -eq 1 ]; then
                innobackupex \
                        --apply-log --use-memory=$restore_buffer_size \
                        --redo-only $base_dir
        elif [ $i -lt $num ]; then
                innobackupex \
                        --apply-log --use-memory=$restore_buffer_size \
                        --redo-only $base_dir \
                        --incremental-dir=$cur_dir
        else
                innobackupex \
                        --apply-log --use-memory=$restore_buffer_size \
                        $base_dir \
                        --incremental-dir=$cur_dir
        fi
        i=$(($i+1))
done

innobackupex --apply-log --use-memory=$restore_buffer_size $base_dir
innobackupex --datadir=${mysql_data_dir} --copy-back $base_dir

chown -R mysql:mysql ${mysql_data_dir}
echo "Restore is done, new datadir is ${mysql_data_dir}"
echo "You can copy to mysql datadir or run a new mysql with this dir!"

使用方法

备份

可配置计划任务做每天的全量备份,然后根据业务量和重要程度每隔10分钟或者半小时做一次增量备份

00 01 * * * sh full_bak.sh "aa bb"#每天凌晨全备
*/30 * * * * sh inc_bak.sh "aa bb"#每隔30分钟增量备份
还原

确认想要还原的时间点,然后执行还原脚本

./restore.sh /backup/20191212 2019-12-12_15-16-07

执行完后,会在指定目录生成一个datadir,这时候可以新开一个实例把数据目录指向这个目录,这时候再从新实例导出想要还原的表格再导入到正式库即可。

这个教程主要应用场景是备份和恢复指定的库,针对误操作(误删之类的)。
如需全备整个库以防机器宕机或磁盘损坏,可参考之前的文章:
innobackupex实现mysql一键备份还原并创建slave同步

[此文参考了其他的一些脚本]