XtraBackup应用说明(支持TokuDB)

背景:

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

安装:

环境:

XtraBackup版本为:2.4
系统版本:14.0416.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服务器上的脚本:

#!/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 = ['zjy@dxyer.com']
                send_mail(mail_list, subject.encode("utf8"), 'Sucess!', "XtraBackup@smtp.dxy.cn", server="smtp.host.dxy")
            else :
                subject = '%s【%s】全量物理备份获取lsn失败' %(today,instance_name)
                mail_list = ['zjy@dxyer.com']
                send_mail(mail_list, subject.encode("utf8"), res, "XtraBackup@smtp.dxy.cn", server="smtp.host.dxy")
        else :
            subject = '%s【%s】全量物理备份失败' %(today,instance_name)
            mail_list = ['zjy@dxyer.com']
            send_mail(mail_list, subject.encode("utf8"), res, "XtraBackup@smtp.dxy.cn", 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 = ['zjy@dxyer.com']
                send_mail(mail_list, subject.encode("utf8"), 'Sucess!', "XtraBackup@smtp.dxy.cn", server="smtp.host.dxy")
            else :
                subject = '%s【%s】增量物理备份失败' %(today,instance_name)
                mail_list = ['zjy@dxyer.com']
                send_mail(mail_list, subject.encode("utf8"), res, "XtraBackup@smtp.dxy.cn", 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 = ['zjy@dxyer.com']
                send_mail(mail_list, subject.encode("utf8"), str(e) , "XtraBackup@smtp.dxy.cn", server="smtp.host.dxy")
View Code

备份服务器B上的脚本:

#!/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 "只在周日执行..."
View Code

模拟全量备份,备份流程原理的信息如下:

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的数据文件看出。

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

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

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

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

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

#解密:在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

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

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字典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一致。

备份相关命令总结:

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热备

 

posted @ 2017-08-22 16:39  jyzhou  阅读(4969)  评论(3编辑  收藏  举报