天天看點

XtraBackup應用說明(支援TokuDB)

背景:

      關于實體備份工具xtrabackup的一些說明可以先看之前寫過的文章說明:XtraBackup 安裝使用和xtrabackup 使用說明(續),本篇文章将介紹xtrabackup在使用中的注意事項和如何全量、增量備份和恢複,包含TokuDB的備份(感謝吳總的推薦)。由于實體備份消耗的空間比較大,是以在工作中一直使用mydumper進行備份,通過邏輯備份雖然空間使用上又很大改善,但是由于還原的時候需要消耗很長時間才能使用,也非常令人頭疼。現在準備在生産環境中使用XtraBackup,記錄使用中的一些注意事項。

安裝:

環境:

XtraBackup版本為:2.4
系統版本:14.04、16.04
MySQL版本:5.7.16      

說明:因為生産環境中有使用到TokuDB引擎,而Percona版本的XtraBackup不支援對TokuDB的備份,是以不能使用官方的版本。不過有人基于官方版本進行了修改,支援Tokudb的備份,下載下傳位址:https://github.com/XeLabs/tokudb-xtrabackup,作者是BohuTANG。編譯安裝過程:

① 下載下傳:

git clone https://github.com/XeLabs/tokudb-xtrabackup.git      

② 安裝依賴包:

apt-get install build-essential flex bison automake autoconf \
   libtool cmake libaio-dev mysql-client libncurses-dev zlib1g-dev \
   libgcrypt11-dev libev-dev libcurl4-gnutls-dev vim-common      

③ 編譯安裝

#程式目錄
mkidr /usr/local/xtrabackup_dir/

#編譯
cd tokudb-xtrabackup

cmake .  -DBUILD_CONFIG=xtrabackup_release  -DWITH_BOOST=extra/boost/boost_1_59_0.tar.gz  -DWITH_MAN_PAGES=OFF  -DCMAKE_INSTALL_PREFIX=/usr/local/xtrabackup_dir/

make VERBOSE=1

make -j8

#安裝
make install      

安裝成功之後,檔案裡的資訊如下:

/usr/local/xtrabackup_dir/bin# ls -lh
總用量 200M
lrwxrwxrwx 1 root root   10  8月 21 11:51 innobackupex -> xtrabackup
-rwxr-xr-x 1 root root 5.2M  8月 21 11:22 xbcloud
-rwxr-xr-x 1 root root 3.0K  8月 21 11:17 xbcloud_osenv
-rwxr-xr-x 1 root root 5.0M  8月 21 11:22 xbcrypt
-rwxr-xr-x 1 root root 5.1M  8月 21 11:22 xbstream
-rwxr-xr-x 1 root root 185M  8月 21 11:32 xtrabackup      

因為包含了一些符号資訊和調試資訊,xtrabackup檔案很大,通過strip進行剝離:

strip xtrabackup       

備份使用說明:

限制:

對于上面編譯好的XtraBackup,對于備份TokuDB引擎有個限制,即不能指定tokudb_data_dir變量,必須使用預設參數。并且MySQL5.7也已經把TokuDB檔案放入到對應的資料庫檔案夾中。      

備份政策:

.每周日進行全量備份,周一至周六進行基于全量備份的增量備份。這樣即使還原周四的備份,也隻要prepare全量和周四增量的備份即可,不需要把周四之前的增量全部apply。
.備份檔案不存本地,直接遠端儲存到備份伺服器。
.備份一個從庫,還原完成直接當從庫來使用。      
MySQL A伺服器(備份)
XtraBackup B備份伺服器
MySQL C伺服器(還原)      

MySQL配置檔案中配置目錄的相關參數:日志檔案(error log、binlog)最好别放資料目錄裡。

innodb_undo_directory   = /var/lib/mysql/undolog/
tokudb_log_dir          = /var/lib/mysql/tokudb_log      

注意:三台伺服器上最好都裝上XtraBackup,并且A和C的MySQL的配置檔案配置的目錄需要一緻,如:undolog目錄、tokudb目錄等。關于備份相關的指令可以看之前寫的文章,本文的備份指令如下:

1)全量備份,每周日進行

/usr/local/xtrabackup_dir/bin/xtrabackup --defaults-extra-file=/etc/mysql/xtrabackup.cnf --datadir=/var/lib/mysql --host=A --no-timestamp --slave-info --safe-slave-backup --ftwrl-wait-query-type=all --history --backup --parallel=5 --compress --compress-threads=3 --stream=xbstream --encrypt=AES256 --encrypt-key-file=/opt/bin/keyfile --encrypt-threads=3 | ssh B "/usr/local/xtrabackup_dir/bin/xbstream -x -C /data/"       

解釋:通過實際情況指定需要的參數,壓縮加密打包到遠端伺服器,并在遠端伺服器解包到指定的目錄。

--defaults-extra-file :該選項指定了在标準defaults-file之前從哪個額外的檔案讀取MySQL配置,必須在指令行的第一個選項的位置。一般用于存備份使用者的使用者名和密碼的配置檔案。
--datadir :backup的源目錄,mysql執行個體的資料目錄。從my.cnf中讀取,或者指令行指定。
--host:該選項表示備份資料庫的位址。
--no-timestamp:該選項可以表示不要建立一個時間戳目錄來存儲備份,指定到自己想要的備份檔案夾。
--slave-info:該選項表示對slave進行備份的時候使用,列印出master的名字和binlog pos,同樣将這些資訊以change 。master的指令寫入xtrabackup_slave_info檔案。
--safe-slave-backup:該選項表示為保證一緻性複制狀态,這個選項停止SQL線程并且等到show status中的slave_open_temp_tables為0的時候開始備份,如果沒有打開臨時表,bakcup會立刻開始,否則SQL線程将關閉直到沒有打開的臨時表。如果slave_open_temp_tables在--safe-slave-backup-timeount(預設300秒)秒之後不為0,從庫sql線程會在備份完成的時候重新開機。
--ftwrl-wait-query-type:該選項表示獲得全局鎖之前允許那種查詢完成,預設是ALL,可選update。
--history:該選項表示percona server 的備份曆史記錄在percona_schema.xtrabackup_history表。
--backup:建立備份并且放入--target-dir目錄中。
--parallel:指定備份時拷貝多個資料檔案并發的程序數,預設值為1。
--compress:該選項表示壓縮innodb資料檔案的備份。
--compress-threads:該選項表示并行壓縮worker線程的數量。
--stream:該選項表示流式備份的格式,backup完成之後以指定格式到STDOUT,目前隻支援tar和xbstream。
--encrypt:該選項表示通過ENCRYPTION_ALGORITHM的算法加密innodb資料檔案的備份,目前支援的算法有ASE128,AES192,AES256。
--encrypt-threads:該選項表示并行加密的worker線程數量。
--encryption-key-file:該選項表示檔案必須是一個簡單二進制或者文本檔案,加密key可通過以下指令行指令生成:openssl rand -base64 24。      

在備份中,備份賬号和密碼存放在/etc/mysql/xtrabackup.cnf中,格式為:

[client]
user=xtrabackup
password=xtrabackup      

生成加密key:

openssl rand -base64 24

echo -n "5V05Dm+aFiRxZ6+sjfplK0K2YlbOplZn" > keyfile      

該備份賬号的權限:

>show grants for xtrabackup@localhost;
+-------------------------------------------------------------------------------------------------------------------------+
| Grants for xtrabackup@localhost                                                                                             |
+-------------------------------------------------------------------------------------------------------------------------+
| GRANT CREATE, RELOAD, PROCESS, SUPER, LOCK TABLES, REPLICATION CLIENT, CREATE TABLESPACE ON *.* TO 'xtrabackup'@'localhost' |
| GRANT SELECT, INSERT, CREATE ON `PERCONA_SCHEMA`.* TO 'xtrabackup'@'localhost'                                              |
+-------------------------------------------------------------------------------------------------------------------------+      

 2)增量備份:每周一至周六執行

/usr/local/xtrabackup_dir/bin/xtrabackup --defaults-extra-file=/etc/mysql/xtrabackup.cnf --datadir=/var/lib/mysql --host=A --no-timestamp --slave-info --safe-slave-backup --ftwrl-wait-query-type=all --history --backup --parallel=5  --compress --compress-threads=3 --stream=xbstream --encrypt=AES256 --encrypt-key-file=/opt/bin/keyfile --encrypt-threads=3 --incremental-lsn=NUM  | ssh B "/usr/local/xtrabackup_dir/bin/xbstream -x -C /data/1/      

解釋:

--incremental-lsn:該選項表示指定增量備份的LSN,與--incremental選項一起使用。      

因為增量備份是根據全量備份(target_dir)來進行的,由于全量已經傳輸到備份伺服器,本地不存備份,是以需要通過記錄當時全量備份時候的LSN,再基于此LSN進行增量備份。

備份資訊說明

1:因為從庫開了多線程複制(slave_parallel_workers),但沒開啟GTID,而XtraBackup要求2者必須都開啟,否則報錯:

The --slave-info option requires GTID enabled for a multi-threaded slave.      

是以在備份腳本裡進行了設定:備份開始前先設定成單線程複制,結束之後設定成多線程;也可以直接開啟GTID。

2:由于開啟了--safe-slave-backup參數,在一定時間裡(--safe-slave-backup-timeout),預設300秒,若slave_open_temp_tables參數大于0則會暫停Slave的SQL線程,等待到沒有打開的臨時表的時候開始備份,備份結束後SQL線程會自動啟動。要是備份時間比較長,少不了報警短信的騷擾。因為我在還原該備份完成之後,會對其進行主從一緻性檢驗,就關閉了該參數進行備份。最終備份的指令如下:

1)全量備份

/usr/local/xtrabackup_dir/bin/xtrabackup --defaults-extra-file=/etc/mysql/xtrabackup.cnf --datadir=/var/lib/mysql --host=A --no-timestamp --slave-info --ftwrl-wait-query-type=all --backup --parallel=5 --compress --compress-threads=3 --stream=xbstream --encrypt=AES256 --encrypt-key-file=/opt/bin/keyfile --encrypt-threads=3 | ssh B "/usr/local/xtrabackup_dir/bin/xbstream -x -C /data/"       

2)增量備份

/usr/local/xtrabackup_dir/bin/xtrabackup --defaults-extra-file=/etc/mysql/xtrabackup.cnf --datadir=/var/lib/mysql --host=A --no-timestamp --slave-info --ftwrl-wait-query-type=all --backup --parallel=5  --compress --compress-threads=3 --stream=xbstream --encrypt=AES256 --encrypt-key-file=/opt/bin/keyfile --encrypt-threads=3 --incremental-lsn=NUM  | ssh B "/usr/local/xtrabackup_dir/bin/xbstream -x -C /data/1/      

注意:編譯的xtrabackup隻支援TokuDB的全量備份,不支援增量備份。

為了友善,把備份指令放到python裡面去執行,定制成一個備份腳本:(備份伺服器B上先建立好目錄。MySQL A伺服器上再執行腳本)

MySQL A伺服器上的腳本:

XtraBackup應用說明(支援TokuDB)
XtraBackup應用說明(支援TokuDB)
#!/usr/bin/env python
#-*- encoding:utf-8 -*-
import os
import sys
import time
import datetime
import smtplib
import subprocess
import re
import MySQLdb

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.Utils import COMMASPACE, formatdate

reload(sys)
sys.setdefaultencoding('utf8')

RETRIES = 1

def retry_times(func):
    def wrapped(*args, **kwargs):
        global RETRIES
        try:
            return func(*args, **kwargs)
        except Exception, err:
            #重試次數
            if RETRIES <= 10:
                print "\n郵件發送重試第【%s】次\n" %RETRIES
                RETRIES += 1
                time.sleep(1)
                if RETRIES == 10:
                    print "\n重試10次,郵件發送失敗,exit...\n"
                    sys.exit()
            return wrapped(*args, **kwargs)
    return wrapped

@retry_times
def send_mail(to, subject, text, from_mail, server="localhost"):
    message = MIMEMultipart()
    message['From'] = from_mail
    message['To'] = COMMASPACE.join(to)
    message['Date'] = formatdate(localtime=True)
    message['Subject'] = subject
    message.attach(MIMEText(text,_charset='utf-8'))
    smtp = smtplib.SMTP(server,timeout=3)
    smtp.sendmail(from_mail, to, message.as_string())
    smtp.close()

def getDate():
    today = datetime.datetime.now().strftime('%Y-%m-%d')
    weekday = datetime.datetime.now().weekday()
    return today,weekday

def getMonDay(num):
    monday = (datetime.date.today() - datetime.timedelta(days=num)).strftime("%Y-%m-%d")
    return monday

def getTime():
    now = datetime.datetime.now().strftime('%H:%M:%S')
    return now

def getPath():
    Path = os.path.realpath(os.path.dirname(__file__))
    return Path

def setSingleThread(conn):
    queries = '''\
STOP SLAVE;\
START SLAVE UNTIL SQL_AFTER_MTS_GAPS;\
SET @@GLOBAL.slave_parallel_workers = 0;\
START SLAVE SQL_THREAD\
'''
    for query in queries.split(';'):
        cursor = conn.cursor()
#        print query
        time.sleep(0.5)
        cursor.execute(query)

def setMultiThread(conn):
    queries = '''\
STOP SLAVE;\
START SLAVE UNTIL SQL_AFTER_MTS_GAPS;\
SET @@GLOBAL.slave_parallel_workers = 4;\
START SLAVE SQL_THREAD\
'''
    for query in queries.split(';'):
        cursor = conn.cursor()
#        print query
        time.sleep(0.5)
        cursor.execute(query)

def run_cmd(cmd):
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    ret_str = p.stdout.read()
    retval = p.wait()
    return ret_str

if __name__ == "__main__":

    CWD = '/etc/mysql'
    db_conf = os.path.join(CWD, 'xtrabackup.cnf')
    conn = MySQLdb.connect(read_default_file=db_conf,host='localhost',port=3306,charset='utf8')

    instance_name = 'Job'
    local_host    = 'localhost'
    remote_host   = 'C'
    today,weekday = getDate()
    weekday = weekday + 1
    print "\n\n\n\n\n備份執行日期是:%s,  星期%s\n" %(today,weekday)
#    today = '2017-08-20'
#    weekday = 7
    if weekday == 7:
        setSingleThread(conn)
        print("\033[0;32m set single thread replication sucess... \033[0m")
        remote_backupfile = '/data/dbbackup_dir/job/%s/full_backup' %today
        print remote_backupfile
        print("\033[0;32m execute full backup... \033[0m")
#--safe-slave-backup --safe-slave-backup-timeout=600
        xtrabackup_fullbackup = '''/usr/local/xtrabackup_dir/bin/xtrabackup --defaults-extra-file=/etc/mysql/xtrabackup.cnf --datadir=/var/lib/mysql --host=%s --no-timestamp --slave-info --ftwrl-wait-query-type=all --backup --parallel=5 --compress --compress-threads=3 --stream=xbstream --encrypt=AES256 --encrypt-key-file=/opt/bin/keyfile --encrypt-threads=3 | ssh %s "/usr/local/xtrabackup_dir/bin/xbstream -x -C %s" ''' %(local_host,remote_host,remote_backupfile)
        print "\n執行全量備份的指令:\n%s\n" %xtrabackup_fullbackup
        res = run_cmd(xtrabackup_fullbackup)
        print res
        setMultiThread(conn)
        print("\033[0;32m set multi thread replication sucess... \033[0m")
        if res.find('completed OK!') > 0:
            _point = re.compile(ur'.*(xtrabackup: The latest check point \(for incremental\): )\'([0-9]+\.?[0-9]*)\'*')
            incremental_point = dict(_point.findall(res)).get('xtrabackup: The latest check point (for incremental): ')
            f = open(os.path.join(getPath(),'incremental_point.txt'),'w')
            f.write(incremental_point)
            f.close()
            if incremental_point:
                subject = '%s【%s】全量實體備份成功' %(today,instance_name)
                mail_list = ['[email protected]']
                send_mail(mail_list, subject.encode("utf8"), 'Sucess!', "[email protected]", server="smtp.host.dxy")
            else :
                subject = '%s【%s】全量實體備份擷取lsn失敗' %(today,instance_name)
                mail_list = ['[email protected]']
                send_mail(mail_list, subject.encode("utf8"), res, "[email protected]", server="smtp.host.dxy")
        else :
            subject = '%s【%s】全量實體備份失敗' %(today,instance_name)
            mail_list = ['[email protected]']
            send_mail(mail_list, subject.encode("utf8"), res, "[email protected]", server="smtp.host.dxy")

    else :
        setSingleThread(conn)
        print("\033[0;32m set single thread replication sucess... \033[0m")
        print("\033[0;32m execute incremental backup... \033[0m")
        monday = getMonDay(weekday)
        remote_backupfile = '/data/dbbackup_dir/job/%s/%s' %(monday,weekday)
#        print remote_backupfile

        try:
            f = open(os.path.join(getPath(),'incremental_point.txt'),'r')
            incremental_point = f.read()
            f.close()
        except Exception,e:
            incremental_point = None
            print e

        if incremental_point:
#--safe-slave-backup --safe-slave-backup-timeout=600
            xtrabackup_incrbackup = '''/usr/local/xtrabackup_dir/bin/xtrabackup --defaults-extra-file=/etc/mysql/xtrabackup.cnf --datadir=/var/lib/mysql --host=%s --no-timestamp --slave-info --ftwrl-wait-query-type=all --backup --parallel=5  --compress --compress-threads=3 --stream=xbstream --encrypt=AES256 --encrypt-key-file=/opt/bin/keyfile --encrypt-threads=3 --incremental-lsn=%s  | ssh %s "/usr/local/xtrabackup_dir/bin/xbstream -x -C %s"''' %(local_host,incremental_point,remote_host,remote_backupfile)
            print "\n執行增量備份的指令:\n%s\n" %xtrabackup_incrbackup
            res = run_cmd(xtrabackup_incrbackup)
            print res
            setMultiThread(conn)
            print("\033[0;32m set multi thread replication sucess... \033[0m")
            if res.find('completed OK!') > 0:
                subject = '%s【%s】增量實體備份成功' %(today,instance_name)
                mail_list = ['[email protected]']
                send_mail(mail_list, subject.encode("utf8"), 'Sucess!', "[email protected]", server="smtp.host.dxy")
            else :
                subject = '%s【%s】增量實體備份失敗' %(today,instance_name)
                mail_list = ['[email protected]']
                send_mail(mail_list, subject.encode("utf8"), res, "[email protected]", server="smtp.host.dxy")

        else :
                setMultiThread(conn)
                print("\033[0;32m set multi thread replication sucess... \033[0m")
                subject = '%s【%s】增量實體備份擷取lsn失敗' %(today,instance_name)
                mail_list = ['[email protected]']
                send_mail(mail_list, subject.encode("utf8"), str(e) , "[email protected]", server="smtp.host.dxy")      

View Code

備份伺服器B上的腳本:

XtraBackup應用說明(支援TokuDB)
XtraBackup應用說明(支援TokuDB)
#!/usr/bin/env python
#-*- encoding:utf-8 -*-
import os
import sys
import time
import datetime
import commands

def getDate():
    today = datetime.datetime.now().strftime('%Y-%m-%d')
    weekday = datetime.datetime.now().weekday()
    return today,weekday

def mkdir(path):
    isExists=os.path.exists(path)
    if not isExists:
        os.makedirs(path)
        print "建立成功!"
    else:
        print "檔案夾存在!"

if __name__ == "__main__":
    today,weekday = getDate()
    weekday = weekday + 1
#    print today,weekday
    if weekday == 7:
#        today = '2017-08-20'
        backup_path  = '/data/dbbackup_dir/'
        instsance_names = ['test','test1','test2']
        dir_names = ['full_backup','1','2','3','4','5','6']
        for instsance_name in instsance_names:
            for dir_name in dir_names:
                dir_path = os.path.join(backup_path,instsance_name,today,dir_name)
                mkdir(dir_path)
    else :
        print "隻在周日執行..."      

模拟全量備份,備份流程原理的資訊如下:

1):fork 一個子線程進行redo log 的複制
2):主線程進行ibd檔案複制,直到ibd檔案複制完
3):SET GLOBAL tokudb_checkpoint_lock=ON,它的作用是允許拿到checkpoint鎖,此時TokuDB的checkpoint會一直block到該鎖釋放(執行前要把tokudb_checkpoint_on_flush_logs關掉),目的是防止拷貝TokuDB資料檔案的過程中做sharp checkpoint(注意:由于不做checkpoint,TokuDB的日志檔案會逐漸增多),進而導緻資料檔案内部不一緻(已拷貝的檔案被修改)
4):LOCK TABLES FOR BACKUP
1.禁止非innodb表更新
2.禁止所有表的ddl
優化點:
1.不會關閉表
2.不會堵塞innodb表的讀取和更新,對于業務表全部是innodb的情況,則備份過程中DML完全不受損。
5):開始并完成備份非InnoDB表和檔案
6):LOCK BINLOG FOR BACKUP,擷取一緻性位點
1.禁止對位點更新的操作
2.允許DDl和更新,直到寫binlog為止。
7):FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS,寫binlog,不輪詢。
8):開始和完成備份TokuDB的undo和redo
9):記錄LSN最後的點,停止redo log的線程的備份
10):解鎖binlog和tables
11):開始和完成備份TokuDB檔案
12):SET GLOBAL tokudb_checkpoint_lock=OFF,解鎖TokuDB的checkpoint鎖。      

增量備份則讀取全量備份時候記錄的點位進行備份(腳本裡把點位寫入到了檔案中)。備份伺服器的目錄如下:

# du -sch 2017-08-20/*
4.0K    2017-08-20/1
4.0K    2017-08-20/2
4.0K    2017-08-20/3
4.0K    2017-08-20/4
4.0K    2017-08-20/5
4.0K    2017-08-20/6
33G    2017-08-20/full_backup
33G    total      

到此,備份大緻的流程已經介紹完畢,那麼接着繼續介紹如何還原。

還原使用說明:

1:全量備份的還原

因為通過上面的備份腳本已經把備份檔案傳輸到了備份伺服器B中,後面的相關操作隻要在備份伺服器B和MySQL伺服器C中進行。

1)從備份伺服器B中,把備份傳到MySQL伺服器C中。如備份目錄為full_backup

scp -r full_backup/ C:/data/dbbackup_dir/      

2)在MySQL伺服器C中進行解密、解壓和prepare。解密的key需要和上面加密時候生成的key保持一緻!解壓需要安裝qpress。

#解密:
for i in `find . -iname "*\.xbcrypt"`; do /usr/local/xtrabackup_dir/bin/xbcrypt -d --encrypt-key-file=/data/keyfile --encrypt-algo=AES256 < $i > $(dirname $i)/$(basename $i .xbcrypt) && rm $i; done

#解壓
for f in `find ./ -iname "*\.qp"`; do qpress -dT2 $f  $(dirname $f) && rm -f $f; done 

#prepare,需要執行2次,第1次復原未送出和執行已送出的事務,第2次生成redo log,加快mysql啟動時間。
/usr/local/xtrabackup_dir/bin/xtrabackup --prepare --apply-log-only --use-memory=1G --target-dir=/data/dbbackup_dir/full_backup      

備份檔案說明:

root@db-test-xt:/data/dbbackup_dir/full_backup# ls -lh xtrabackup_*
-rw-r--r-- 1 root root   27 Aug 22 10:28 xtrabackup_binlog_info
-rw-r--r-- 1 root root   27 Aug 22 10:28 xtrabackup_binlog_pos_innodb
-rw-r--r-- 1 root root  121 Aug 22 10:28 xtrabackup_checkpoints
-rw-r--r-- 1 root root  687 Aug 22 10:27 xtrabackup_info
-rw-r--r-- 1 root root 8.0M Aug 22 10:28 xtrabackup_logfile
-rw-r--r-- 1 root root   83 Aug 22 10:24 xtrabackup_slave_info      
xtrabackup_binlog_info:記錄備份時的binlog點位,若有MyISAM存儲引擎,以該點位準。

xtrabackup_binlog_pos_innodb:記錄備份時的binlog點位,用于InnoDB、XtraDB的點位記錄。

xtrabackup_checkpoints:記錄備份模式(backup_type)以及放備份的起始位置beginlsn和結束位置endlsn等。

xtrabackup_slave_info:備份從庫時記錄的CHANGE資訊。

xtrabackup_info:備份的具體資訊,如備份指令、版本、開始結束時間、是否壓縮、加密等資訊。      

經過上面的解密、解壓、prepare之後,資料庫的檔案已經生成,現在需要做的就是把這些檔案放到MySQL資料目錄中。

3)還原,複制檔案

注意:備份和還原的MySQL配置檔案所配置的目錄需要保持一緻,如:undolog是否獨立,tokudb必須不能指定目錄,保證備份和還原MySQL目錄的一緻性。如果起來當一個從來服務則需要修改server_id。

1:複制檔案到資料目錄
/data/dbbackup_dir# mv full_backup/* /var/lib/mysql/

2:根據配置檔案設定目錄
/var/lib/mysql# mkdir undolog
/var/lib/mysql# mv undo00* undolog/

3:修改權限
/var/lib# chown -R mysql.mysql mysql/

4:确定好目錄沒問題之後,就可以直接開啟MySQL      

如果MySQL已經正常啟動,隻需要執行start slave,不需要change就可以直接成為一個從服務。如果擔心主從資料的一緻性問題,可以通過主從一緻性檢驗來保證。

2:增量備份的還原

上面已經模拟進行了周日全量備份,現在模拟在上面的全量基礎上進行的增量備份。在進行全量備份時的LSN已經寫入到了檔案incremental_point.txt中,該檔案和備份腳本在同一級目錄。

還是和全量備份一樣,執行上面給出的定制備份腳本,如執行時間是周二,執行完後備份伺服器的目錄如下:

# du -sch 2017-08-20/*
4.0K    2017-08-20/1
8.2G    2017-08-20/2
4.0K    2017-08-20/3
4.0K    2017-08-20/4
4.0K    2017-08-20/5
4.0K    2017-08-20/6
33G    2017-08-20/full_backup
41G    total      

可以看到增量備份目錄是2,這裡需要注意的是:真正的增量其實是對InnoDB的增量,而MyISAM和TokuDB還是直接拷貝檔案的全量資料。可以通過增量備份列印出來的資訊或則看增量備份的MyISAM、TokuDB的資料檔案看出。

增量備份的備份流程和全量備份一樣,可以直接看全量備份的說明即可,那麼接着繼續介紹如何進行增量+全量的還原。

1)從備份伺服器B中,把備份傳到MySQL伺服器C中。如備份目錄為2

scp -r 2/ C:/data/dbbackup_dir/      
#解密:在full_backup和2目錄裡執行
for i in `find . -iname "*\.xbcrypt"`; do /usr/local/xtrabackup_dir/bin/xbcrypt -d --encrypt-key-file=/data/keyfile --encrypt-algo=AES256 < $i > $(dirname $i)/$(basename $i .xbcrypt) && rm $i; done

#解壓:在full_backup和2目錄裡執行
for f in `find ./ -iname "*\.qp"`; do qpress -dT2 $f  $(dirname $f) && rm -f $f; done 
      
#prepare full_backup
/usr/local/xtrabackup_dir/bin/xtrabackup --prepare --apply-log-only --use-memory=1G --target-dir=/data/dbbackup_dir/full_backup      

這裡需要注意全量備份的中繼資料中的資訊(/data/dbbackup_dir):

# cat full_backup/xtrabackup_checkpoints 
backup_type = log-applied
from_lsn = 0
to_lsn = 370623694056
last_lsn = 370623694065
compact = 0
recover_binlog_info = 0

# cat full_backup/xtrabackup_slave_info 
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin-3306.000368', MASTER_LOG_POS=48441381;      

基于全量備份的增量prepare,可以先删除全量備份目錄下的ib_buffer_pool,不然會在prepare增量的時候報錯,不過不影響後續操作。

xtrabackup: Can't create/write to file './ib_buffer_pool' (Errcode: 17 - File exists)
[00] error: cannot open the destination stream for /ib_buffer_pool
[00] Error: copy_file() failed.      

接着應用增量備份

#prepare 2
/usr/local/xtrabackup_dir/bin/xtrabackup --prepare --apply-log-only --use-memory=1G --target-dir=/data/dbbackup_dir/full_backup --incremental-dir=/data/dbbackup_dir/2      

這裡需要注意增量備份中中繼資料的資訊(/data/dbbackup_dir),和全量備份中進行對比:

# cat 2/xtrabackup_checkpoints 
backup_type = incremental
from_lsn = 370623694056    #對應全量備份中的to_lsn
to_lsn = 371913526149
last_lsn = 371913526158
compact = 0
recover_binlog_info = 1

# cat 2/xtrabackup_slave_info
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin-3306.000368', MASTER_LOG_POS=637921806;    #對應的binlog不一樣      

在prepare增量備份期間,可以看到一些資訊:

①:undolog會被增量追加,如:

xtrabackup: page size for /data/dbbackup_dir/2//undo001.delta is 16384 bytes
Applying /data/dbbackup_dir/2//undo001.delta to ./undo001...      

②:共享表空間被增量追加,如:

xtrabackup: page size for /data/dbbackup_dir/2//ibdata1.delta is 16384 bytes
Applying /data/dbbackup_dir/2//ibdata1.delta to ./ibdata1...      

③:ibd檔案被增量追加,如:

xtrabackup: page size for /data/dbbackup_dir/2//test/test.ibd.delta is 16384 bytes
Applying /data/dbbackup_dir/2//test/test.ibd.delta to ./test/test.ibd...      

④:frm、MYI、MYD被全量複制,如:

170822 14:04:51 [01] Copying /data/dbbackup_dir/2/test/test.frm to ./test/test.frm
170822 14:04:51 [01]        ...done      

⑤:沒有看到TokuDB的增量和全量追加和複制,而且增量perpare完之後,全量備份裡的tokudb檔案被删除。

到這裡增量備份已經prepare完成了,此時全量備份裡的一些中繼資料檔案已經被修改:

# cat full_backup/xtrabackup_checkpoints 
backup_type = full-prepared
from_lsn = 0
to_lsn = 371913526149    #已經把增量放進來了
last_lsn = 371913526158
compact = 0
recover_binlog_info = 0

# cat full_backup/xtrabackup_slave_info
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin-3306.000368', MASTER_LOG_POS=637921806; #更新成增量的資訊      

因為不支援TokuDB的增量,而且由于進行增量的prepare,導緻全量備份裡的tokudb檔案被删除,是以需要手動進行複制TokuDB檔案。從增量備份裡複制tokudb相關的所有檔案到全量備份,如:

/data/dbbackup_dir# mv 2/test/*tokudb full_backup/test/

/data/dbbackup_dir# mv 2/tokudb_log/* full_backup/tokudb_log/
/data/dbbackup_dir# mv 2/tokudb.directory full_backup/
/data/dbbackup_dir# mv 2/tokudb.environment full_backup/
/data/dbbackup_dir# mv 2/__tokudb_lock_dont_delete_me_data full_backup/
/data/dbbackup_dir# mv 2/tokudb.rollback full_backup/      

要是不确定那些庫有TokuDB引擎,可以通過下面的指令來檢視和複制,來替換mv xxx/*.tokudb

#在增量備份裡執行
/data/dbbackup_dir/2#for i in `find . -iname "*\.tokudb"`; do echo "mv $i ../full_backup/"$dirname $i; done | awk -F "/ ./" '{print $1"/"$2}'      

最後再次prepare全量備份,生成redo log:

/usr/local/xtrabackup_dir/bin/xtrabackup  --prepare  --use-memory=1G --target-dir=/data/dbbackup_dir/full_backup      

到此已經生成了還原所需要的所有檔案,隻需要把這些檔案放到資料目錄即可。

1:複制檔案到資料目錄
/data/dbbackup_dir# mv full_backup/* /var/lib/mysql/

2:根據配置檔案設定目錄
/var/lib/mysql# mkdir undolog
/var/lib/mysql# mv undo00* undolog/

3:修改權限
/var/lib# chown -R mysql.mysql mysql/

4:确定好目錄沒問題之後,就可以直接開啟MySQL      

如果MySQL已經正常啟動,隻需要執行start slave,不需要change就可以直接成為一個從服務。如果擔心主從資料的一緻性問題,可以通過主從一緻性檢驗來保證。後續如果遇到什麼“坑”,會持續更新。

補充

如何處理一張表的還原呢?因為XtraBackup是整個執行個體還原的,是以對于還原恢複單個表的操作可以這樣操作(必須開啟innodb_file_per_table),用下面的方法替換原有的prepare方法,隻需要執行一次即可:

xtrabackup --prepare --export --target-dir=/data/dbbackup_dir/full_backup      

用export方法,執行完後,資料庫目錄下的表檔案格式會試這樣:

test.cfg  #包含了Innodb字典dump
test.exp
test.frm
test.ibd      

單表恢複還原:

1:先在MySQL裡discard該表空間
mysql> alter table test discard tablespace;

2:在備份目錄裡把需要的表檔案複制到資料庫目錄下
上述的cfg、ibd、frm、exp的表檔案複制過去
cp ...  ...

3:最後在MySQL裡import該表空間
mysql> alter table test import tablespace;

4:驗證      

總結

到此,關于XtraBackup的全量、增量備份還原已經介紹完,總的來說:想要進行實體備份并且有TokuDB引擎,官方的版本不支援,需要使用BohuTANG改版過的XtraBackup,相容官方版本。并且主要注意下面的情況:

1:不能設定tokudb_data_dir;
2:不能自動的增量備份TokuDB,需要手動的複制Tokudb檔案。
3:備份和還原的MySQL大版本保持一緻,而且設定目錄的參數也要一樣。
4:盡量不要使用MyISAM,用InnoDB替換MyISAM,減少鎖表時間。
5:加密的keyfile必須要和解密的keyfile一緻。      

備份相關指令總結:

XtraBackup應用說明(支援TokuDB)
XtraBackup應用說明(支援TokuDB)
1:普通全量備份 
xtrabackup --defaults-extra-file=/etc/mysql/uupp.cnf --datadir=/var/lib/mysql --host=172.16.109.132 --log-copy-interval=10 --no-timestamp --slave-info --safe-slave-backup --backup --parallel=5  --target-dir=/data/3306

2:壓縮全量備份:qpress
xtrabackup --defaults-extra-file=/etc/mysql/uupp.cnf --datadir=/var/lib/mysql --host=172.16.109.132 --log-copy-interval=10 --no-timestamp --slave-info --safe-slave-backup --backup --parallel=5 --compress --compress-threads=3 --target-dir=/data/3306

3:壓縮加密全量備份
xtrabackup --defaults-extra-file=/etc/mysql/uupp.cnf --datadir=/var/lib/mysql --host=172.16.109.132 --log-copy-interval=10 --no-timestamp --slave-info --safe-slave-backup --backup --parallel=5 --compress --compress-threads=3 --encrypt=AES256 --encrypt-key-file=/data/keyfile --encrypt-threads=3  --target-dir=/data/3306

4:打包壓縮加密全量備份:
xtrabackup --defaults-extra-file=/etc/mysql/uupp.cnf --datadir=/var/lib/mysql --host=172.16.109.132 --log-copy-interval=10 --no-timestamp --slave-info --safe-slave-backup --backup --parallel=5 --compress --compress-threads=3 --stream=xbstream --encrypt=AES256 --encrypt-key-file=/data/keyfile --encrypt-threads=3  --target-dir=/data/3306/ > /data/3306/all_db.xbstream

5:打包壓縮加密傳輸到遠端伺服器,并在遠端伺服器解包
xtrabackup --defaults-extra-file=/etc/mysql/uupp.cnf --datadir=/var/lib/mysql --host=172.16.109.132 --log-copy-interval=10 --no-timestamp --slave-info --safe-slave-backup --backup --parallel=5 --compress --compress-threads=3 --stream=xbstream --encrypt=AES256 --encrypt-key-file=/data/keyfile --encrypt-threads=3  --target-dir=/data/3306/ | ssh 172.16.109.133 "xbstream -x -C /data/"



#解包
xbstream -x < all_db.xbstream 

#解密
for i in `find . -iname "*\.xbcrypt"`; do /usr/local/xtrabackup_dir/bin/xbcrypt -d --encrypt-key-file=/data/keyfile --encrypt-algo=AES256 < $i > $(dirname $i)/$(basename $i .xbcrypt) && rm $i; done

#解壓
for f in `find ./ -iname "*\.qp"`; do qpress -dT2 $f  $(dirname $f) && rm -f $f; done 

#apply
xtrabackup --prepare --apply-log-only --use-memory=1G --target-dir=/data/3306      

View Code 

參考文檔

XtraBackup 使用說明

MySQL · TokuDB · 讓Hot Backup更完美

TokuDB· HA方案·TokuDB熱備

~~~~~~~~~~~~~~~

萬物之中,希望至美

~~~~~~~~~~~~~~~

繼續閱讀