这几天使用Xtrabackup实现了下mysql的全库备份和恢复,这里和你们分享下实现的思路。html
关于Xtrabackup(又或innobackupex)的介绍这里就不啰嗦了,感兴趣的同窗请移步官方文档,这里只要知道它提供了mysql备份和恢复的功能就能够了。mysql
Xtrabackup提供了全量备份和增量备份两种方式,全量就不解释了,增量是指其能够只备份指定位置后的新增数据。本文介绍的增量备份方法使用到了LSN(Log Sequence Number)
,能够从备份成功文件夹的xtrabackup_checkpoints
文件中获取,其中to_lsn
就是下次增量备份的起始位置。
结合二者,咱们能够获得下图的备份思路。sql
解释以下:数据库
因为全量备份和增量备份的命令参数不一样,因此首先要判断是否须要全量备份。app
若是是全量备份,那么便执行命令,备份成功后,记录xtrabackup_checkpoints
文件中的to_lsn
,以便后面进行增量备份。ssh
若是是增量备份,那么首先读取上次备份时记录下的to_lsn
,若是读取失败,报错并结束。不然执行相应命令,备份成功后记录to_lsn
。socket
一个简单的实现脚本,咱们叫它backup.sh,以下所示:this
#!/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
中每小时增量备份一次就能够了。spa
注意--parallel=6
使用是有条件的,参见文档。rest
下面是备份文件夹的效果图。
一旦线上数据库发生宕机之类的灾难性事故,备份数据就要立马发挥做用了。所谓养兵千日,用兵一时。打开备份文件夹一看,如上面的图,每小时一个压缩文件,时间久了,茫茫多,上百个压缩文件,简直是必定的,这必须得来个脚本自动化恢复数据才成。思路很简单,见下图:
解释以下:
一个简单的实现脚本,咱们叫它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
就能够了。
数据库还没备份呢?!还看呢?!赶忙动起来!