Xtrabackup
Xtrabackup是由percona开源的免费数据库热备份软件,它能对InnoDB数据库和XtraDB存储引擎的数据库非阻塞地备份(对于MyISAM的备份同样需要加表锁);mysqldump备份方式是采用的逻辑备份,其最大的缺陷是备份和恢复速度较慢,如果数据库大于50G,mysqldump备份就不太适合。
Xtrabackup优点
1)备份速度快,物理备份可靠
2)备份过程不会打断正在执行的事务(无需锁表)
3)能够基于压缩等功能节约磁盘空间和流量
4)自动备份校验
5)还原速度快
6)可以流传将备份传输到另外一台机器上
Xtrabackup原理
Xtrabackup安装完成后有4个可执行文件,其中2个比较重要的备份工具是innobackupex、xtrabackup
1)xtrabackup 是专门用来备份InnoDB表的,不能备份非Innodb表,和mysql server没有交互;
2)innobackupex 是一个脚本,用来备份非InnoDB表,同时会调用xtrabackup命令来备份InnoDB表,还会和mysql server交互,比如锁表、获取位置点等。简单地说,就是在xtrabackup基础上做了一层封装;
3)xbcrypt 加密解密备份工具
4)xbstream 流传打包传输工具,类似tar
1)在使用InnoDB引擎表内部会维护一个redo日志文件,我们也可以叫做事务日志文件。事务日志会存储每一个InnoDB表数据的记录修改
2)xtrabackup在启动时会记住log sequence number(LSN)日志序列号,即当前的redo记录的位置,并且复制所有数据文件
3)复制过程需要一些时间,所以这期间如果数据文件LSN有改动,它会运行一个后台进程,用于监控事务日志,并不停地将事务日志中每个数据文件的修改都记下来
Xtrabackup安装
官网下载Xtrabackup
1 ##https://www.percona.com/downloads/XtraBackup/Percona-XtraBackup-2.3.5/binary/RedHat/6/x86_64/percona-xtrabackup-2.3.5-1.el6.x86_64.rpm
搜索下载几个依赖rpm包
##http://rpmfind.net/linux/RPM/
perl-DBI-1.609-4.el6.x86_64.rpm
perl-DBD-MySQL-4.013-3.el6.x86_64.rpm
libev-4.04-2.el6.x86_64.rpm
安装完成后检查rpm包安装情况
[root@db02 tools]# rpm -ivh percona-xtrabackup-2.3.5-1.el6.x86_64.rpm
warning: percona-xtrabackup-2.3.5-1.el6.x86_64.rpm: Header V4 DSA/SHA1 Signature, key ID cd2efd2a: NOKEY
Preparing... ########################################### [100%]
1:percona-xtrabackup ########################################### [100%]
[root@db02 tools]# rpm -qa|grep xtrabackup
percona-xtrabackup-2.3.5-1.el6.x86_64
[root@db02 tools]# rpm -ql percona-xtrabackup-2.3.5-1.el6.x86_64
/usr/bin/innobackupex #innobackupex脚本工具
/usr/bin/xbcloud
/usr/bin/xbcloud_osenv
/usr/bin/xbcrypt
/usr/bin/xbstream
/usr/bin/xtrabackup #最主要的备份工具
/usr/share/doc/percona-xtrabackup-2.3.5
/usr/share/doc/percona-xtrabackup-2.3.5/COPYING
/usr/share/man/man1/innobackupex.1.gz
/usr/share/man/man1/xbcrypt.1.gz
/usr/share/man/man1/xbstream.1.gz
/usr/share/man/man1/xtrabackup.1.gz
先对数据库做一个全量备份
[root@db02 data]# innobackupex --defaults-file=/data/3306/my.cnf --user=root --password=li123456 /backup/full/
...
60710 08:24:47 [00] Writing backup-my.cnf
160710 08:24:47 [00] ...done
160710 08:24:47 [00] Writing xtrabackup_info
160710 08:24:47 [00] ...done
xtrabackup: Transaction log of lsn (1672995) to (1672995) was copied.
160710 08:24:47 completed OK!
此时可以看到/backup/full已经有了备份过来的数据文件
[root@db02 full]# cd /backup/full/2016-07-10_08-24-43/
[root@db02 2016-07-10_08-24-43]# ll
总用量 131108
-rw-r----- 1 root root 387 7月 10 08:24 backup-my.cnf
-rw-r----- 1 root root 134217728 7月 10 08:24 ibdata1
drwx------ 2 root root 4096 7月 10 08:24 lichengbing
drwx------ 2 root root 4096 7月 10 08:24 lilongzi
drwx------ 2 root root 4096 7月 10 08:24 mysql
drwx------ 2 root root 4096 7月 10 08:24 performance_schema
-rw-r----- 1 root root 21 7月 10 08:24 xtrabackup_binlog_info
-rw-r----- 1 root root 113 7月 10 08:24 xtrabackup_checkpoints #记录LSN号文件
-rw-r----- 1 root root 503 7月 10 08:24 xtrabackup_info
-rw-r----- 1 root root 2560 7月 10 08:24 xtrabackup_logfile
[root@db02 2016-07-10_08-24-43]# cat xtrabackup_checkpoints
backup_type = full-backuped #备份类型为全备
from_lsn = 0 #起始LSN号(由于是全备所以起始LSN号为0开始)
to_lsn = 1672995 #截止LSN号
last_lsn = 1672995
compact = 0
recover_binlog_info = 0
现在全备已经完成了,我们来模拟破坏数据,然后恢复数据。
首先停掉数据库
[root@db02 3306]# mysqladmin -uroot -pli123456 -S /data/3306/mysql.sock shutdown
[root@db02 3306]# mv /data/3306/data/ /data/3306/data_bak/
[root@db02 3306]# mkdir -p /data/3306/data/ #必须创建一个新的空data文件夹用来恢复,不然恢复会报错
Original data directory /data/3306/data is not empty!
此时我们在开启数据库,发现数据库文件被破坏无法启动了
[root@db02 3306]# mysqld_safe --defaults-file=/data/3306/my.cnf &
160710 10:05:14 mysqld_safe Logging to '/data/3306/mysql_oldboy3306.err'.
160710 10:05:14 mysqld_safe Starting mysqld daemon with databases from /data/3306/data
160710 10:05:15 mysqld_safe mysqld from pid file /data/3306/mysqld.pid ended
# pid进程文件无法启动
[1]+ Done mysqld_safe --defaults-file=/data/3306/my.cnf
[root@db02 3306]# tail mysql_oldboy3306.err
160710 10:05:15 InnoDB: 5.5.32 started; log sequence number 1595668
160710 10:05:15 [Note] Recovering after a crash using /data/3306/mysql-bin
160710 10:05:15 [Note] Starting crash recovery...
160710 10:05:15 [Note] Crash recovery finished.
160710 10:05:15 [Note] Server hostname (bind-address): '0.0.0.0'; port: 3306
160710 10:05:15 [Note] - '0.0.0.0' resolves to '0.0.0.0';
160710 10:05:15 [Note] Server socket created on IP: '0.0.0.0'.
160710 10:05:15 [ERROR] Fatal error: Can't open and lock privilege tables: Table 'mysql.host' doesn't exist #提示相关数据库表未找到
160710 10:05:15 mysqld_safe mysqld from pid file /data/3306/mysqld.pid ended
准备全量恢复
[root@db02 3306]# innobackupex --defaults-file=/data/3306/my.cnf --user=root --password=li123456 --apply-log /backup/full/2016-07-10_08-24-43/
...
InnoDB: Waiting for purge to start
InnoDB: 5.6.24 started; log sequence number 1673228
xtrabackup: starting shutdown with innodb_fast_shutdown = 1
InnoDB: FTS optimize thread exiting.
InnoDB: Starting shutdown...
InnoDB: Shutdown completed; log sequence number 1673238
160710 08:42:01 completed OK!
#这里的apply-log参数意思就是在正真恢复数据库数据之前,先将数据库redo日志状态恢复
接下来才是将数据文件恢复
[root@db02 3306]# innobackupex --defaults-file=/data/3306/my.cnf --copy-back /backup/full/2016-07-10_08-24-43/
...
160710 08:43:41 [01] ...done
160710 08:43:41 [01] Copying ./mysql/user.frm to /data/3306/data/mysql/user.frm
160710 08:43:41 [01] ...done
160710 08:43:41 [01] Copying ./mysql/tables_priv.MYI to /data/3306/data/mysql/tables_priv.MYI
160710 08:43:41 [01] ...done
160710 08:43:41 [01] Copying ./mysql/proxies_priv.MYI to /data/3306/data/mysql/proxies_priv.MYI
160710 08:43:41 [01] ...done
160710 08:43:41 completed OK!
再更改数据文件属组,启动数据库成功
[root@db02 3306]# chown -R mysql.mysql data
[root@db02 data]# mysqld_safe --defaults-file=/data/3306/my.cnf &
[1] 90409
[root@db02 data]# mysql -uroot -pli123456 -S /data/3306/mysql.sock
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| lichengbing | #数据表恢复成功
| lilongzi |
| mysql |
| performance_schema |
+--------------------+
5 rows in set (0.00 sec)
再来模拟一下增量备份
新插入几行数据
[root@db02 opt]# mysql -uroot -pli123456 -S /data/3306/mysql.sock lichengbing < /opt/test2.sql
mysql> select * from lichengbing.test;
+----+-------+
| id | name |
+----+-------+
| 1 | one |
| 2 | two |
| 3 | three |
| 4 | four | #此时4、5、6相当于数据库增量文件
| 5 | five |
| 6 | six |
+----+-------+
6 rows in set (0.00 sec)
增量备份
[root@db02 opt]# innobackupex --defaults-file=/data/3306/my.cnf --user=root --password=li123456 --incremental /backup/add/ --incremental-basedir=/backup/full/2016-07-10_08-24-43/
...
160710 08:55:15 [00] Writing xtrabackup_info
160710 08:55:15 [00] ...done
xtrabackup: Transaction log of lsn (1673693) to (1673693) was copied.
160710 08:55:15 completed OK!
[root@db02 add]# cd /backup/add/2016-07-10_08-55-12/
[root@db02 2016-07-10_08-55-12]# cat xtrabackup_checkpoints
backup_type = incremental
from_lsn = 1672995 #增量备份的起始LSN号是靠读取全备xtrabackup_checkpoints文件得到的
to_lsn = 1673693 #增量结束LSN号
last_lsn = 1673693
compact = 0
recover_binlog_info = 0
增量恢复
增量恢复和全量恢复有着一些不同,需要注意的是:
1)需要在每个备份(包括完全备份和增量备份)上,将已经提交的事务进行“重放”,重放之后,所有的备份数据将合并到完全备份上;
2)基于所有备份将未提交的事务进行“回滚”
关闭数据库
[root@db02 ~]# mysqladmin -uroot -pli123456 -S /data/3306/mysql.sock shutdown
执行完全备份的前滚
[root@db02 ~]# innobackupex --defaults-file=/data/3306/my.cnf --user=root --pli123456 --apply-log --redo-only /backup/full/2016-07-10_08-24-43/
##--redo-only 在做增量恢复时,全量和增量备份的数据文件在恢复前必须将在重做日志文件中的已提交的事务前滚!此参数将会合并全备和增量备份的数据文件,但不包括最后一次增量备份的数据文件
将全备和增备合并
[root@db02 ~]# innobackupex --defaults-files=/data/3306/my.cnf --user=root --pli123456 --apply-log /backup/full/2016-07-10_08-24-43/ --incremental-dir=/backup/add/2016-07-10_08-55-12/
##/backup/full/2016-07-10_08-24-43/ 全备目录
##--incremental-dir=/backup/add/2016-07-10_08-55-12/ 增量目录
##--redo-only 只有一次增备,所以不需要加这个参数,如果有N次增备,依次恢复增备,除了最后一个每次都要加 --redo-only的参数
破坏数据库,将全备和增备恢复回来
[root@db02 3306]# rm -fr data_bak
[root@db02 3306]# mv data data_bak
[root@db02 3306]# innobackupex --defaults-file=/data/3306/my.cnf --copy-back /backup/full/2016-07-10_08-24-43/
...
160710 09:54:54 [01] ...done
160710 09:54:54 [01] Copying ./mysql/user.frm to /data/3306/data/mysql/user.frm
160710 09:54:54 [01] ...done
160710 09:54:54 [01] Copying ./mysql/tables_priv.MYI to /data/3306/data/mysql/tables_priv.MYI
160710 09:54:54 [01] ...done
160710 09:54:55 [01] Copying ./mysql/proxies_priv.MYI to /data/3306/data/mysql/proxies_priv.MYI
160710 09:54:55 [01] ...done
160710 09:54:55 completed OK!
[root@db02 3306]# chown -R mysql.mysql data
恢复成功,登陆查看
1234567891011121314 [root@db02 data]# mysqld_safe --defaults-file=/data/3306/my.cnf &
[root@db02 data]# mysql -uroot -pli123456 -S /data/3306/mysql.sock
mysql> select * from lichengbing.test;
+----+-------+
| id | name |
+----+-------+
| 1 | one |
| 2 | two |
| 3 | three |
| 4 | four |
| 5 | five |
| 6 | six |
+----+-------+
6 rows in set (0.00 sec)
其他一些备份示例
指定数据库备份
[root@db02 each]# innobackupex --defaults-file=/data/3306/my.cnf --user=root --password=li123456 --databases="lichengbing" /backup/each/
指定表备份
[root@db02 each]# innobackupex --defaults-file=/data/3306/my.cnf --user=root --password=li123456 --databases="lichengbing test" /backup/each/
以压缩格式备份
[root@db02 full]# innobackupex --defaults-file=/data/3306/my.cnf --user=root --password=li123456 --stream=tar /backup/full/|gzip>/backup/full/back_`date +%F`.tar.gz