天天看点

MySQL备份恢复之XtraBackup

一、 简介

        我们知道,针对innodb存储引擎,mysql本身没有提供合适的热备工具,ibbackup虽是一款高效的首选热备方式,但它是是收费的。好在percona公司给大家提供了一个开源、免费的xtrabackup热备工具,它可实现ibbackup的所有功能,并且还扩展支持真正的增量备份功能,是商业备份工具innodb hotbackup的一个很好的替代品。

xtrabackup包括两个主要工具:xtrabackup和innobackupex:

xtrabackup只能备份innodb和xtradb两种引擎表,而不能备份myisam数据表。

innobackupex则是参考innodbhotbackup的innoback脚本修改而来的一个perl脚本,它封装了xtrabackup,主要是为了能方便的同时备份innodb和myisam引擎表。但在处理myisam时需要加一个读锁,这会阻塞线上服务的写操作,所以数据库中myisam表越少越好。另外,该工具还加入了一些其它使用选项,比如slave-info,可以在备份中记录一些slave需要的信息,根据这些信息,可以很方便的利用备份重做slave。

        通过xtrabackup,不但可在线(热)备份整个库的innodb、xtradb表,还可在上一次整库备份的基础上做增量备份(innodb only),其工作原理如下:

        首先完成一个完全备份,并记录下此时检查点的lsn(log sequence number);在进行增量备份时,比较表空间中每个页的lsn是否大于上次备份时的lsn,如果是,则备份该页,同时记录当前检查点的lsn。

注意:在增量备份时,作为备份基础的全备文件不能压缩,否则备份失效;另外,增量备份期间,表结构变更的话,变更部分的备份也会失效。

二、安装

         pecona官方网站提供了xtrabackup源码包、二进制包以及rpm包三种安装包,下载地址为:http://www.percona.com/downloads/xtrabackup/ 本文选择最简单方便的rpm包安装,如下:

[root@db ~]# rpm -ivh percona-xtrabackup-2.0.5-499.rhel5.x86_64.rpm

warning: percona-xtrabackup-2.0.5-499.rhel5.x86_64.rpm:header v4 dsa signature: nokey, key id cd2efd2a

preparing...               ########################################### [100%]

  1:percona-xtrabackup    ########################################### [100%]

   安装完成后,会在/usr/bin/目录下生成如下命令工具:

[root@db ~]# cd /usr/bin/

[root@db bin]# ls xtr* inno*

innobackupex    innochecksum xtrabackup_51  xtrapchar  xtrapinfo xtrapproto  xtrapstats

innobackupex-1.5.1  xtrabackup   xtrabackup_55  xtrapin    xtrapout  xtrapreset

其中:

innobackupex                                 是备份时直接使用的工具,它是一个perl脚本,内部封装xtrabackup;

innobackupex-1.5.1                       是innobackupex文件的一个软链接;

xtrabackup                                       是备份innodb引擎的脚本;

xtrabackup_51                                xtrabackup运行时需要调用的工具,适用于mysql 5.1版本;

xtrabackup_55                                xtrabackup运行时需要调用的工具,适用于mysql 5.5版本;

三、xtrabackup的使用

        首先来学习使用xtrabackup这个命令工具,前面提到:它只能备份innodb和xtradb两种引擎表,不能备份myisam数据表。

通过--help参数查看该命令的用法,如下:

usage: [xtrabackup  [--default-file=#]   --backup |  xtrabackup [--defaults-file=#] --prepare] [options]

参数解读如下:

<col>

--defaults-file=#

标识默认的配置文件,可显式手工指定,也可不设置;若不设置,则xtrabackup缺省将从以下目录查找配置文件:

/etc/my.cnf    

/etc/mysql/my.cnf       

/usr/local/etc/my.cnf 

~/.my.cnf 

然后从中读取[mysqld]和[xtrabackup]配置段。[mysqld]中只需指定datadir、innodb_data_home_dir、innodb_data_file_path、innodb_log_group_home_dir、innodb_log_files_in_group、innodb_log_file_size这6个参数即可让xtrabackup正常工作。

--defaults-extra-file=#

如果使用了该参数,则会在读取了全局配置文件后,再读取这里指定的配置文件

--target-dir=name

备份文件的存放路径

--backup 

 执行备份操作,将备份文件存放到target-dir指定的目录下

--prepare

对备份文件执行恢复前的准备(生成innodb logfile)

--print-param

打印备份或恢复时需要的参数

--use-memory=# 

该参数在prepare的时候使用,控制prepare时innodb实例使用的内存量

--suspend-at-end

 在target-dir目录下产生一个xtrabackup_suspended文件,将xtrabackup进程挂起,不停地将数据文件的变化同步到备份文件,直到用户手工删除xtrabackup_suspended文件

--throttle=#

每秒钟io次数,限制backup时使用的i/o操作量,使备份对数据库正常业务的影响最小化

--log-stream 

该参数在backup时使用,将xtrabackup_logfile的内容输出到标准输出,使用该参数时会自动使用suspend-at-end参数,innobackupex脚本的stream模式会使用该参数。

--incremental-lsn=name

增量备份时只拷贝lsn比该参数指定值新的ibd pages,前次备份到了哪个lsn可以看前次备份集的xtrabackup_checkpoints文件

--incremental-basedir=name

该参数在backup的时候使用,备份比该参数指定位置的备份集新的idb pages

--incremental-dir=name

该参数在prepare的时候使用,指定prepare时产生的delta文件和日志文件的存放路径

--tables=name

在备份file-per-table类型的文件时使用,使用正则表达式指定需要备份的innodb表

-h, --datadir=name

mysql数据库的数据文件目录

示例1:完全备份与恢复(innodb)

(1)备份

脚本内容:

[root@db xtrabak]# more xtra_backup.sh 

# 2014-04-29

mkdir -p /data/xtrabak/bak_`date +%f`/

echo "backup begin" `date`

xtrabackup --defaults-file=/etc/my.cnf --backup --target-dir=/data/xtrabak/bak_`date +%f`/

cp -r /var/lib/mysql/test /data/xtrabak/bak_`date +%f`/

注意:xtrabackup只备份数据文件,并不备份数据表结构文件(.frm),所以还需手动拷贝一下,以便xtrabackup恢复时使用

执行备份脚本:

[root@db xtrabak]# sh xtra_backup.sh 

backup begin tue apr 29 15:22:09 cst 2014

xtrabackup version 2.0.5 for percona server 5.1.59 unknown-linux-gnu (x86_64) (revision id: 499)

xtrabackup: uses posix_fadvise().

xtrabackup: cd to /var/lib/mysql/

xtrabackup: target instance is assumed as followings.

xtrabackup:   innodb_data_home_dir = /var/lib/mysql

xtrabackup:   innodb_data_file_path = ibdata1:10m:autoextend

xtrabackup:   innodb_log_group_home_dir = /var/lib/mysql

xtrabackup:   innodb_log_files_in_group = 2

xtrabackup:   innodb_log_file_size = 5242880

&gt;&gt; log scanned up to (1830807)

[01] copying /var/lib/mysql/ibdata1 to /data/xtrabak/bak_2014-04-29/ibdata1

[01]        ...done

xtrabackup: the latest check point (for incremental): ‘1830807‘

xtrabackup: stopping log copying thread.

.&gt;&gt; log scanned up to (1830807)

xtrabackup: transaction log of lsn (1830807) to (1830807) was copied.

从输出可以看出,备份过程首先记录lsn,然后拷贝数据文件(注意,并没有备份表结构文件.frm),最后拷贝并记录lsn。备份完成后,在指定目标目录除了拷贝过来的数据文件ibdata1及表结构文件夹test外,还生成了另外两个文件,分别记录日志及检查点,如下:

[root@db xtrabak]# cd bak_2014-04-29/

[root@db bak_2014-04-29]# ls

ibdata1  test  xtrabackup_checkpoints  xtrabackup_logfile

恢复

删除库test,然后通过备份文件执行恢复,如下:

[root@db xtrabak]# more xtra_prepare.sh 

xtrabackup --defaults-file=/etc/my.cnf --prepare --target-dir=/data/xtrabak/bak_`date +%f`/

cp -r /data/xtrabak/bak_`date +%f`/test/ /var/lib/mysql/

rm /var/lib/mysql/ib*

cp /data/xtrabak/bak_`date +%f`/ib* /var/lib/mysql/

chown -r mysql:mysql /var/lib/mysql

service mysql restart

说明:脚本中步骤依次为:

实施对备份文件进行恢复前的准备;

从备份文件拷贝数据表结构到默认的数据目录;

删除默认数据目录中对应的数据文件并复制备份的数据文件到默认数据目录;

修改默认数据目录权限并重启mysql服务

执行恢复脚本:

[root@db xtrabak]# sh xtra_prepare.sh 

xtrabackup: cd to /data/xtrabak/bak_2014-04-29/

xtrabackup: this target seems to be not prepared yet.

xtrabackup: xtrabackup_logfile detected: size=2097152, start_lsn=(1830807)

xtrabackup: temporary instance for recovery is set as followings.

xtrabackup:   innodb_data_home_dir = ./

xtrabackup:   innodb_log_group_home_dir = ./

xtrabackup:   innodb_log_files_in_group = 1

xtrabackup:   innodb_log_file_size = 2097152

xtrabackup: starting innodb instance for recovery.

xtrabackup: using 104857600 bytes for buffer pool (set by --use-memory parameter)

innodb: the innodb memory heap is disabled

innodb: mutexes and rw_locks use gcc atomic builtins

innodb: compressed tables use zlib 1.2.3

140429 15:28:34  innodb: initializing buffer pool, size = 100.0m

140429 15:28:34  innodb: completed initialization of buffer pool

140429 15:28:34  innodb: highest supported file format is barracuda.

innodb: the log sequence number in ibdata files does not match

innodb: the log sequence number in the ib_logfiles!

140429 15:28:34  innodb: database was not shut down normally!

innodb: starting crash recovery.

innodb: reading tablespace information from the .ibd files...

innodb: last mysql binlog file position 0 85912, file name ./mysql-bin.000026

140429 15:28:34 percona xtradb (http://www.percona.com) 1.0.17-12.5 started; log sequence number 1830807

[notice (again)]

  if you use binary log and don‘t use any hack of group commit,

  the binary log position seems to be:

xtrabackup: starting shutdown with innodb_fast_shutdown = 1

140429 15:28:34  innodb: starting shutdown...

140429 15:28:34  innodb: shutdown completed; log sequence number 1832037

shutting down mysql....                                    [  ok  ]

starting mysql.                                            [  ok  ]

执行完成后,检查发现test库已成功恢复。

示例2:增量备份与恢复

增量备份是以完全备份或上一次增量备份为基础的备份,适合数据库很大的情况,支持在线热备,备份期间不锁定表,不影响用户使用,备份恢复效率都比较高。

下面我们来模拟一次增量备份:

(1)  完全备份

现在test库有三张表,执行一次完全备份

--脚本内容:

[root@db xtrabak]# more xtra_full_bak.sh 

mkdir -p /data/xtrabak/full_bak_`date +%f`/

xtrabackup --defaults-file=/etc/my.cnf --backup --target-dir=/data/xtrabak/full_bak_`date +%f`/

cp -r /var/lib/mysql/test/ /data/xtrabak/full_bak_`date +%f`/

--执行脚本

[root@db xtrabak]# sh xtra_full_bak.sh 

xtrabackup: cd to /var/lib/mysql

xtrabackup:   innodb_log_files_in_group = 3

xtrabackup:   innodb_log_file_size = 67108864

&gt;&gt; log scanned up to (1653514)

[01] copying /var/lib/mysql/ibdata1 to /data/xtrabak/full_bak_2014-04-29/ibdata1

xtrabackup: the latest check point (for incremental): ‘1653514‘

.&gt;&gt; log scanned up to (1653514)

xtrabackup: transaction log of lsn (1653514) to (1653514) was copied.

执行完成后,查看备份文件

[root@db xtrabak]# cd full_bak_2014-04-29/

[root@db full_bak_2014-04-29]# ls

(2)  增量备份

向test库中添加一张新表,然后执行增量备份

[root@db xtrabak]# more xtra_delta_bak.sh 

mkdir -p /data/xtrabak/delta_bak_`date +%f`/

xtrabackup --defaults-file=/etc/my.cnf --backup --target-dir=/data/xtrabak/delta_bak_`date +%f`/ --incremental-basedir=/data/xtrabak/full_bak_`date +%f`/

说明:这里需要再次拷贝test库的表结构文件,因为期间可能会增加或删除表

[root@db xtrabak]# sh xtra_delta_bak.sh 

incremental backup from 1653514 is enabled.

&gt;&gt; log scanned up to (1660436)

[01] copying /var/lib/mysql/ibdata1 to /data/xtrabak/delta_bak_2014-04-29/ibdata1.delta

xtrabackup: the latest check point (for incremental): ‘1660436‘

.&gt;&gt; log scanned up to (1660436)

xtrabackup: transaction log of lsn (1660436) to (1660436) was copied.

[root@db xtrabak]# cd delta_bak_2014-04-29/

[root@db delta_bak_2014-04-29]# ls

ibdata1.delta  ibdata1.meta  xtrabackup_checkpoints  xtrabackup_logfile

注意:在增量备份目录下,数据文件是以.delta结尾的,增量备份只备份上一次完全备份后被修改过的page;当然,若再次执行增量备份,可以上一次完全备份为基础,也可以第一次增量备份为基础,每次增量备份的目录都是需要修改的。

(3)  恢复

删除test库,模拟故障,然后通过完全备份及增量备份文件执行恢复。

[root@db xtrabak]# more xtra_delta_prepare.sh 

xtrabackup --defaults-file=/etc/my.cnf --prepare --target-dir=/data/xtrabak/full_bak_`date +%f`/

xtrabackup --defaults-file=/etc/my.cnf --prepare --target-dir=/data/xtrabak/full_bak_`date +%f`/ --incremental-dir=/data/xtrabak/delta_bak_`date +%f`/

cp -r /data/xtrabak/full_bak_`date +%f`/test/ /var/lib/mysql/

cp /data/xtrabak/full_bak_`date +%f`/ib* /var/lib/mysql/

[root@db xtrabak]# sh xtra_delta_prepare.sh 

xtrabackup: cd to /data/xtrabak/full_bak_2014-04-29/

xtrabackup: xtrabackup_logfile detected: size=2097152, start_lsn=(1653514)

140429 18:28:21  innodb: initializing buffer pool, size = 100.0m

140429 18:28:21  innodb: completed initialization of buffer pool

140429 18:28:21  innodb: highest supported file format is barracuda.

140429 18:28:21  innodb: database was not shut down normally!

innodb: last mysql binlog file position 0 2596, file name ./mysql-bin.000043

140429 18:28:22 percona xtradb (http://www.percona.com) 1.0.17-12.5 started; log sequence number 1653514

140429 18:28:22  innodb: starting shutdown...

140429 18:28:22  innodb: shutdown completed; log sequence number 1653514

xtrabackup: this target seems to be already prepared.

xtrabackup: xtrabackup_logfile detected: size=2097152, start_lsn=(1660436)

xtrabackup:   innodb_log_group_home_dir = /data/xtrabak/delta_bak_2014-04-29/

xtrabackup: page size for /data/xtrabak/delta_bak_2014-04-29//ibdata1.delta is 16384 bytes

applying /data/xtrabak/delta_bak_2014-04-29//ibdata1.delta to ././ibdata1...

140429 18:28:22  innodb: initializing buffer pool, size = 100.0m

140429 18:28:22  innodb: completed initialization of buffer pool

140429 18:28:22  innodb: highest supported file format is barracuda.

140429 18:28:22  innodb: database was not shut down normally!

innodb: last mysql binlog file position 0 2703, file name ./mysql-bin.000045

140429 18:28:22 percona xtradb (http://www.percona.com) 1.0.17-12.5 started; log sequence number 1660436

140429 18:28:23  innodb: shutdown completed; log sequence number 1660436

shutting down mysql...                                     [  ok  ]

starting mysql.....                                        [  ok  ]

执行成功后,检查发现test数据库已成功恢复。

四、 innobackupex使用

        前面提到,innobackupex可同时备份innodb和myisam引擎表,所以通常都直接使用innobackupex。需要注意的是my.cnf中必须加上datadir这个参数,因为要根据它来定位innodb引擎的数据文件位置。

innobackupex也包含一系列参数,可通过innobackupex --help命令查看,此处不逐一说明了。

下面我们通过一个完整的示例来演示其用法,如下:

(1)  备份

[root@db xtrabak]# more backup.sh 

log=innobackupex_`date +%f`.log

str=bak_`date +%f`

innobackupex --user=root --password=root123 --defaults-file=/etc/my.cnf --stream=tar /data/xtrabak/$str/ 2&gt;/data/xtrabak/$log | gzip&gt;/data/xtrabak/$str/base.tar.gz

echo "backup end" `date`

cp /etc/my.cnf /data/xtrabak/my_`date +%f`.cnf

--执行脚本:

[root@db xtrabak]# sh backup.sh 

backup begin wed apr 30 16:15:02 cst 2014

backup end wed apr 30 16:15:27 cst 2014

[root@db xtrabak]# cd bak_2014-04-30/

[root@db bak_2014-04-30]# ls

base.tar.gz

执行完成后,生成备份文件的压缩包

(2)  增量日志备份

由于数据库不停的对外提供服务,备份之后的操作会记录到binlong日志文件中,所以我们还应备份后续的日志文件。

此处删除几张表,并切换日志以模拟真实环境,备份完整的binlog日志文件;然后关闭数据库,删除数据库所有文件,以便模拟故障。

--脚本内容(binlog备份到远程机器):

[root@db xtrabak]# more binlog_bak.sh 

cd /var/lib/

date=`date -d ‘-1 hour‘ +%y%m%d%h00`

touch -t "${date}" starttemp

echo "$date"

umount /mnt_log&gt;/dev/null 2&gt;&amp;1

mount -t nfs 192.168.3.108:/logcenter /mnt_log

find /var/lib/mysql/mysql-bin.* -newer starttemp|xargs -i {} cp -p {} /mnt_log/mysql-binlog/192.168.3.28/

# umount -t nfs /mnt_log

[root@db xtrabak]# more prepare.sh 

# 2014-04-30

service mysql stop

mkdir -p /data/xtrabak/prepare_`date +%f`/

tar -ixzvf /data/xtrabak/bak_`date +%f`/base.tar.gz -c /data/xtrabak/prepare_`date +%f`/

innobackupex --apply-log --user=root --defaults-file=/etc/my.cnf /data/xtrabak/prepare_`date +%f`/

innobackupex --copy-back --user=root --defaults-file=/etc/my.cnf /data/xtrabak/prepare_`date +%f`/

chown -r mysql:mysql /var/lib/mysql/

rm -rf /var/lib/mysql/xtrabackup_binlog_pos_innodb

--完全备份恢复后,通过binlog进行增量恢复

[root@db xtrabak]# mysqlbinlog --start-position="******" /data/log/mysql-bin.****** |mysql -uroot -p

注意:start-position的位置可通过解压后的备份文件查看,如下:

[root@db xtrabak]# cd prepare_2014-04-30/

[root@db prepare_2014-04-30]# more xtrabackup_binlog_info 

mysql-bin.000047        1472

或者

[root@db prepare_2014-04-30]# more xtrabackup_binlog_pos_innodb 

./mysql-bin.000047      1472

成功恢复后,mysql即可正常使用。