2

这几天使用Xtrabackup实现了下mysql的全库备份和恢复,这里和大家分享下实现的思路。

关于Xtrabackup(又或innobackupex)的介绍这里就不啰嗦了,感兴趣的同学请移步官方文档,这里只要知道它提供了mysql备份和恢复的功能就可以了。

备份思路

Xtrabackup提供了全量备份和增量备份两种方式,全量就不解释了,增量是指其可以只备份指定位置后的新增数据。本文介绍的增量备份方法使用到了LSN(Log Sequence Number),可以从备份成功文件夹的xtrabackup_checkpoints文件中获取,其中to_lsn就是下次增量备份的起始位置。
结合两者,我们可以得到下图的备份思路。

2621559725.jpg

解释如下:

  1. 由于全量备份和增量备份的命令参数不同,所以首先要判断是否需要全量备份。

  2. 如果是全量备份,那么便执行命令,备份成功后,记录xtrabackup_checkpoints文件中的to_lsn,以便后面进行增量备份。

  3. 如果是增量备份,那么首先读取上次备份时记录下的to_lsn,如果读取失败,报错并结束。否则执行相应命令,备份成功后记录to_lsn

一个简单的实现脚本,我们叫它backup.sh,如下所示:

#!/bin/sh
# xtrabackup的相关配置
INNOBACKUPEX="innobackupex "
MY_CNF="/home/config/mysql/3307.backup.cnf"
MY_USER="xtrabackup"
MY_PASSWORD="xtrabackup"
MY_SOCKET="/home/socket/mysql/3307.sock"
# 远程备份机 文件名配置
REMOTE_HOST="dbbackup"
REMOTE_DIR="/home/backup/mysql/test"
LOCAL_LSN_FILE="~/.to_lsn_important"
DATE_NAME=`date +%Y-%m-%d-%H-%M-%S`
REMOTE_FILE=$DATE_NAME.tar.gz
LOCK_FILE="~/.mysql.backup.lock"
LOCAL_BACKUP_DIR="/home/backup/mysql/test/$DATE_NAME"
# 输出帮助信息
function usage()
{
 echo "Usage:"
 echo "-f db will be backuped fully with this parameter. If not , incrementally. "
}
#防止同时执行两个备份命令,发生冲突
if [ -f $LOCK_FILE ] ;then
 echo 'Mysql backup lockfile is locked!'
 exit 0
fi
full=0
while getopts "fh" arg #选项后面的冒号表示该选项需要参数
do
 case $arg in
 f) 
 full=1
 ;;
 h) # 输出帮助信息
 usage
 exit 0
 ;;
 esac
done
echo "backup dir is $REMOTE_DIR/$REMOTE_FILE"
# backup up db to remote host
echo "start to backup db!"`date +%Y-%m-%d-%H-%M-%S`
if [ "$full"x = "1"x ] ;then
 # 全量备份
 echo '1' > $LOCK_FILE
 $INNOBACKUPEX --defaults-file=$MY_CNF --user=$MY_USER --password=$MY_PASSWORD --socket=$MY_SOCKET ./ --stream=tar | gzip | ssh $REMOTE_HOST "cat - > $REMOTE_DIR/FULL-$REMOTE_FILE"
 ssh $REMOTE_HOST "cd $REMOTE_DIR;rm -f xtrabackup_checkpoints;tar zxfi $REMOTE_DIR/FULL-$REMOTE_FILE xtrabackup_checkpoints "
 toLSN=$( ssh $REMOTE_HOST "cat $REMOTE_DIR/xtrabackup_checkpoints|grep to_lsn|awk -F= '{gsub(/ /,\"\",\2ドル);print \2ドル}'" )
 if [ $toLSN ] ;then
 echo $toLSN > $LOCAL_LSN_FILE
 else
 echo 'no lsn from remote host!please check!'
 fi
else
 # 增量备份
 if [ -f $LOCAL_LSN_FILE ] ;then
 toLSN=`cat $LOCAL_LSN_FILE`
 fi
 if [ ! $toLSN ] ;then
 echo 'last LSN is not set !please check!'
 exit 0
 fi
 echo '1' > $LOCK_FILE
 mkdir -p $LOCAL_BACKUP_DIR
 echo "last to lsn is "$toLSN
 $INNOBACKUPEX --parallel=6 --defaults-file=$MY_CNF --user=$MY_USER --password=$MY_PASSWORD --socket=$MY_SOCKET --incremental --incremental-lsn=$toLSN $LOCAL_BACKUP_DIR 2>/tmp/innobackexLog
 toLSN=$( cd $LOCAL_BACKUP_DIR/*; cat xtrabackup_checkpoints|grep to_lsn|awk -F= '{gsub(/ /,"",2ドル);print 2ドル}' )
 echo "new to lsn is "$toLSN;
 if [ $toLSN ] ;then
 echo $toLSN > $LOCAL_LSN_FILE
 cd $LOCAL_BACKUP_DIR/*;tar zc .|ssh $REMOTE_HOST "cat - > $REMOTE_DIR/$REMOTE_FILE"
 echo "save file to $REMOTE_HOST @ $REMOTE_DIR/$REMOTE_FILE"
 else
 echo 'no lsn from local backup file!delete remote backup file!'$LOCAL_BACKUP_DIR/$REMOTE_FILE
 fi
 echo "remove $LOCAL_BACKUP_DIR"
 rm -rf $LOCAL_BACKUP_DIR
fi
rm -f $LOCK_FILE
echo "end to backup db!"`date +%Y-%m-%d-%H-%M-%S`

将上述脚本配置好后,放到mysql主机上,执行 sh backup.sh -f进行全量备份,之后将sh backup.sh添加到crontab中每小时增量备份一次就可以了。

注意--parallel=6使用是有条件的,参见文档

下面是备份文件夹的效果图。
767148255.png

恢复思路

一旦线上数据库发生宕机之类的灾难性事故,备份数据就要立马发挥作用了。所谓养兵千日,用兵一时。打开备份文件夹一看,如上面的图,每小时一个压缩文件,时间久了,茫茫多,上百个压缩文件,简直是一定的,这必须得来个脚本自动化恢复数据才成。思路很简单,见下图:
3423403848.jpg

解释如下:

  1. 先解压,没啥说的。
  2. 找到全量备份的数据,因为增量备份也是以此为基准进行的。上面备份的时候,全量备份文件命名以FULL开头便是为了此处便于查找。
  3. 先恢复全量备份数据,然后按照时间顺序恢复增量备份的数据。
  4. 将数据恢复到mysql中
  5. 启动mysql,连上看看有没问题。

一个简单的实现脚本,我们叫它restore.sh,如下所示:

#!/bin/sh
BACK_DIR="/home/backup/mysql/test"
RESTORE_DIR="/home/tmpback/test"
# xtrabackup恢复时使用的配置文件可能与数据库配置文件不同
RESTORE_MY_CNF="/home/config/mysql/3307.backup.cnf"
# 启动mysql需要的配置文件,按需设定
MY_CNF="/home/config/mysql/3307.cnf"
MY_DATA_DIR="/home/data/mysql/3307"
MY_SOCK_DIR="/home/socket/mysql/"
MY_LOG_DIR="/home/logs/mysqld/3307"
#extract all tar file
fullFileName=""
for file in $( ls $BACK_DIR | grep "tar.gz" )
do
 fileName=${file%.tar.gz}
 full=${file%%-*}
 if [ "${full}"x = "FULL"x ] ;then
 fullFileName=$fileName
 fi
 DEST_DIR="$RESTORE_DIR/$fileName"
 if [ -d $DEST_DIR ] ;then
 echo "$DEST_DIR exists!"
 else
 mkdir -p $DEST_DIR
 echo "start to extract file $file to $DEST_DIR"
 tar zxif $BACK_DIR/$file -C $RESTORE_DIR/$fileName
 echo "end to extract file "$file
 fi
done
echo "full backup dir is "$fullFileName
echo "**start to repare full backup dir"
# 恢复全量数据
echo "innobackupex --apply-log --redo-only --use-memory=4G $RESTORE_DIR/$fullFileName"
innobackupex --apply-log --redo-only --use-memory=4G "$RESTORE_DIR/$fullFileName"
echo "**end to repare full backup dir"
# 恢复增量数据
for file in $( ls $RESTORE_DIR|grep -v "FULL" )
do
 echo "**start to repare $file"
 echo "innobackupex --apply-log --redo-only --use-memory=4G $RESTORE_DIR/$fullFileName --incremental-dir=$RESTORE_DIR/$file"
 innobackupex --apply-log --redo-only --use-memory=4G "$RESTORE_DIR/$fullFileName" --incremental-dir="$RESTORE_DIR/$file"
 echo "**end to repare $file"
done
echo "**start to copy back data to mysql"
rm -rf $MY_DATA_DIR
mkdir $MY_DATA_DIR
mkdir $MY_SOCK_DIR
mkdir $MY_LOG_DIR
#将数据恢复到mysql中
echo "innobackupex --defaults-file=$RESTORE_MY_CNF --copy-back $RESTORE_DIR/$fullFileName"
innobackupex --defaults-file=$RESTORE_MY_CNF --copy-back $RESTORE_DIR/$fullFileName
echo "**end to copy back data to mysql"
chown -R mysql:mysql $MY_DATA_DIR
chown -R mysql:mysql $MY_SOCK_DIR
chown -R mysql:mysql $MY_LOG_DIR
echo "All data has been restored! Try to start mysql now"
echo "mysqld_multi --defaults-file=$MY_CNF start 1"

使用方法很简单,配置好后,直接运行sh restore.sh就可以了。

小结

数据库还没备份呢?!还看呢?!赶紧动起来!


rockybean
917 声望64 粉丝

« 上一篇
下一篇 »
tcp自连接问题

引用和评论

0 条评论
评论支持部分 Markdown 语法:**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用 @ 来通知其他用户。

AltStyle によって変換されたページ (->オリジナル) /