Mysql備份和恢復的一種可行方案---Xtrabackup

這幾天使用Xtrabackup實現了下mysql的全庫備份和恢復,這裏和你們分享下實現的思路。html

關於Xtrabackup(又或innobackupex)的介紹這裏就不囉嗦了,感興趣的同窗請移步官方文檔,這裏只要知道它提供了mysql備份和恢復的功能就能夠了。mysql

備份思路

Xtrabackup提供了全量備份和增量備份兩種方式,全量就不解釋了,增量是指其能夠只備份指定位置後的新增數據。本文介紹的增量備份方法使用到了LSN(Log Sequence Number),能夠從備份成功文件夾的xtrabackup_checkpoints文件中獲取,其中to_lsn就是下次增量備份的起始位置。
結合二者,咱們能夠獲得下圖的備份思路。sql

2621559725.jpg

解釋以下:數據庫

  1. 因爲全量備份和增量備份的命令參數不一樣,因此首先要判斷是否須要全量備份。app

  2. 若是是全量備份,那麼便執行命令,備份成功後,記錄xtrabackup_checkpoints文件中的to_lsn,以便後面進行增量備份。ssh

  3. 若是是增量備份,那麼首先讀取上次備份時記錄下的to_lsn,若是讀取失敗,報錯並結束。不然執行相應命令,備份成功後記錄to_lsnsocket

一個簡單的實現腳本,咱們叫它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

下面是備份文件夾的效果圖。
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就能夠了。

小結

數據庫還沒備份呢?!還看呢?!趕忙動起來!

相關文章
相關標籤/搜索