XtraBackup应用说明(支持TokuDB)

背景:

      关于物理备份工具xtrabackup的一些说明可以先看之前写过的文章说明:XtraBackup 安装使用和xtrabackup 使用说明(续),本篇文章将介绍xtrabackup在使用中的注意事项和如何全量、增量备份和恢复,包含TokuDB的备份(感谢吴总的推荐)。由于物理备份消耗的空间比较大,所以在工作中一直使用mydumper进行备份,通过逻辑备份虽然空间使用上又很大改善,但是由于还原的时候需要消耗很长时间才能使用,也非常令人头疼。现在准备在生产环境中使用XtraBackup,记录使用中的一些注意事项。

安装:

环境:

XtraBackup版本为:2.4系统版本:14.04、16.04MySQL版本: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=1make -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 24echo -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服务器上的脚本:


#!/usr/bin/env python#-*- encoding:utf-8 -*-import osimport sysimport timeimport datetimeimport smtplibimport subprocessimport reimport MySQLdbfrom email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipartfrom email.Utils import COMMASPACE, formatdate

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

RETRIES = 1def 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_timesdef 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,weekdaydef getMonDay(num):
    monday = (datetime.date.today() - datetime.timedelta(days=num)).strftime("%Y-%m-%d")    return mondaydef getTime():
    now = datetime.datetime.now().strftime('%H:%M:%S')    return nowdef getPath():
    Path = os.path.realpath(os.path.dirname(__file__))    return Pathdef 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_strif __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")


备份服务器B上的脚本:


#!/usr/bin/env python#-*- encoding:utf-8 -*-import osimport sysimport timeimport datetimeimport commandsdef getDate():
    today = datetime.datetime.now().strftime('%Y-%m-%d')
    weekday = datetime.datetime.now().weekday()    return today,weekdaydef 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 BACKUP1.禁止非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和redo9):记录LSN最后的点,停止redo log的线程的备份10):解锁binlog和tables11):开始和完成备份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_backup33G    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/18.2G    2017-08-20/24.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的数据文件看出。

增量备份的备份流程和全量备份一样,可以直接看全量备份的说明即可,那么接着继续介绍如何进行增量+全量的还原。

因为通过上面的备份脚本已经把备份文件传输到了备份服务器B中,后面的相关操作只要在备份服务器B和MySQL服务器C中进行。

1)从备份服务器B中,把备份传到MySQL服务器C中。如备份目录为2

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

2)在MySQL服务器C中进行解密、解压和prepare。解密的key需要和上面加密时候生成的key保持一致!解压需要安装qpress。

 i  ` . -iname `;  /usr/local/xtrabackup_dir/bin/xbcrypt -d --encrypt-key-=/data/keyfile --encrypt-algo=AES256 < $i > $( $i)/$( $i .xbcrypt) &&  $i;  f  ` ./ -iname `;  qpress -dT2 $f  $( $f) &&  -f $f;
#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-appliedfrom_lsn = 0to_lsn = 370623694056last_lsn = 370623694065compact = 0recover_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 = incrementalfrom_lsn = 370623694056    #对应全量备份中的to_lsnto_lsn = 371913526149last_lsn = 371913526158compact = 0recover_binlog_info = 1# cat 2/xtrabackup_slave_infoCHANGE 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 bytesApplying /data/dbbackup_dir/2//undo001.delta to ./undo001...

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

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

③:ibd文件被增量追加,如:

xtrabackup: page size for /data/dbbackup_dir/2//test/test.ibd.delta is 16384 bytesApplying /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.frm170822 14:04:51 [01]        ...done

⑤:没有看到TokuDB的增量和全量追加和复制,而且增量perpare完之后,全量备份里的tokudb文件被删除。

到这里增量备份已经prepare完成了,此时全量备份里的一些元数据文件已经被修改:


# cat full_backup/xtrabackup_checkpoints 
backup_type = full-preparedfrom_lsn = 0to_lsn = 371913526149    #已经把增量放进来了last_lsn = 371913526158compact = 0recover_binlog_info = 0# cat full_backup/xtrabackup_slave_infoCHANGE MASTER TO MASTER_LOG_FILE='mysql-bin-3306.000368', MASTER_LOG_POS=637921806; #更新成增量的信息


因为不支持TokuDB的增量,而且由于进行增量的prepare,导致全量备份里的tokudb文件被删除,所以需要手动进行复制TokuDB文件。从增量备份里复制tokudb相关的所有文件到全量备份,如:


/data/dbbackup_dir#  /test


要是不确定那些库有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

到此已经生成了还原所需要的所有文件,只需要把这些文件放到数据目录即可。

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就可以直接成为一个从服务。如果担心主从数据的一致性问题,可以通过主从一致性检验来保证。后续如果遇到什么“坑”,会持续更新。

补充

如何处理一张表的还原呢?因为XtraBackup是整个实例还原的,所以对于还原恢复单个表的操作可以这样操作(必须开启innodb_file_per_table),用下面的方法替换原有的prepare方法,只需要执行一次即可

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

export方法,执行完后,数据库目录下的表文件格式会试这样:

test.cfg  #包含了Innodb字典dumptest.exptest.frmtest.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,兼容官方版本。并且主要注意下面的情况:

:尽量不要使用MyISAM,用InnoDB替换MyISAM,减少锁表时间。
:加密的keyfile必须要和解密的keyfile一致。

备份相关命令总结:


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.xbstream5:打包压缩加密传输到远程服务器,并在远程服务器解包
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 

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


 

参考文档

XtraBackup 使用说明

MySQL · TokuDB · 让Hot Backup更完美

TokuDB· HA方案·TokuDB热备