使用xtrabackup备份MySQL数据库

Java学习 2020-01-17

前言

Xtrabackup提供了两种命令行工具:

  • xtrabackup:专用于备份InnoDB和XtraDB引擎的数据;
  • innobackupex:是一个perl脚本,在执行过程中会调用xtrabackup命令,这个命令即可以实现备份InnoDB,也可以备份Myisam引擎的对象。

xtrabackup是由percona提供的MySQL数据库备份工具,其备份速度快并且可靠;备份过程不会打断正在执行的事务;能够基于压缩等功能节约磁盘空间和流量;自动实现备份检验;还原速度快。

若需要安装xtrabackup,可以移步其官方网站,在其官网上提供了多种安装方式。

博文大纲:

  • 一、安装xtrabackup及其插件
  • 二、xtrabackup完全备份+binlog增量备份
  • 三、xtrabackup完全备份+xtrabackup增量备份
  • 四、innobackupex全库备份+innobackupex增量备份

注:二、三、四是三种不同的备份方案,在生产环境中选择合适的一种即可。

一、安装xtrabackup及其插件

1、yum安装xtrabackup

参考官方文档,在官方文档上提供了各个版本的帮助说明。

[ ~]# yum -y install https://repo.percona.com/yum/percona-release-latest.noarch.rpm  
[ ~]# yum -y install percona-xtrabackup-24

xtrabackup中主要包含两个工具:

  • xtrabackup:是用于热备份innodb,xtradb表中数据的工具,支持在线热备份,可以在不加锁的情况下备份innodb数据表,不过该工具不能操作myisam引擎表。
  • innobackupex:是将xtrabackup进行封装的perl脚本,能同时处理innodb和myisam,但在处理myisam时需要加一个读锁,由于操作myisam时需要加读锁,所以会堵塞线上服务的写操作,而Innodb没有这样的限制。

2、下载并安装percona-toolkit工具

[ test]# yum -y install perl-DBI perl-DBD-MySQL perl-Time-HiRes perl-IO-Socket-SSL perl-TermReadKey.x86_64 perl-Digest-MD5
[ test]# wget https://www.percona.com/downloads/percona-toolkit/2.2.19/RPM/percona-toolkit-2.2.19-1.noarch.rpm
[ test]# rpm -ivh percona-toolkit-2.2.19-1.noarch.rpm

二、xtrabackup完全备份+binlog增量备份

1、创建备份目录

[ test]# mkdir -p /opt/mysqlbackup/{full,inc}
# full:全备存放的目录
# inc:增量备份存放的目录

2、创建备份用户

[ test]# mysql -uroot -p123.com
mysql> create user ‘localhost‘ identified by ‘123.com‘;
mysql> revoke all privileges,grant option from ‘bakuser‘@‘localhost‘;
mysql> grant reload,lock tables,replication client,process on *.* to ‘localhost‘;
mysql> flush privileges;

3、完全备份

[ test]# innobackupex --user=bakuser --password=123.com /opt/mysqlbackup/full/
#当备份完成后将出现以下提示信息
.............  #忽略部分信息
200116 13:09:21 completed OK!

上述执行相关解释如下:

  • --user:指定连接数据库的用户名;
  • --password:指定连接数据库的密码;
  • --defaults-file:指定数据库的配置文件my.cnf,innobackupex要从其中获取datadir等信息,如果不指定,则会默认去搜索my.cnf这个文件,搜索顺序和mysql启动时的搜索顺序一样;
  • --database:指定要备份的数据据库,这里指定的数据库只对myisam表有效,对于innodb数据来说都是全备(所有数据库中的innodb数据都进行了备份,不是只备份指定的数据库,恢复时也一样);
  • /opt/mysqlbackup/full:是备份文件的存放位置。

4、查看备份后的文件

使用xtrabackup备份MySQL数据库

各个文件存放的内容如下:

  • backup-my.cnf:备份命令用到的配置选项信息;
  • ib_buffer_pool:buffer缓冲区相关的信息;
  • xtrabackup_checkpoints:这个文件很重要,保存的是备份类型(如完全或增量)、备份状态(如是否已经为perpared状态(备份恢复前需要的状态)),和LSN(日志序列号)范围信息,每个innodb页(一般为16k大小)都会包含一个日志序列号,LSN时整个数据库系统同的系统版本号,每个页面相关的LSN能够表明此页面最近是如何发生改变的。
  • xtrabackup_info:备份指令相关的信息。

5、通过二进制日志进行增量备份

在进行增量备份前,需要先查看到完全备份时binlog日志位置(position),如下:

[ 2020-01-17_10-39-52]# pwd
/opt/mysqlbackup/full/2020-01-17_10-39-52
[ 2020-01-17_10-39-52]# cat xtrabackup_binlog_info 
bin_log.000001  154
# 得到完全备份是备份到了bin_log.000001二进制日志中的154的位置

通过二进制日志进行增量备份:

在增量备份前,自行向数据库中进行增删改等操作,以便产生新的二进制日志。

[ ~]# mysqlbinlog --start-position=154 /usr/local/mysql/data/bin_log.000001 > /opt/mysqlbackup/inc/`date +%F`.sql

6、模拟数据丢失,以便还原数据

[ ~]# rm -rf /usr/local/mysql/data/*      #直接删除本地所有数据

还原完全备份的大概流程如下:

  • 准备(prepare)一个完全备份,一般情况下,在备份完成后,数据还不能用于恢复操作,因为备份的数据中可能包含尚未提交的事务或已经提交但尚未同步至数据文件中的事务。因此,此时数据文件仍处于不一致状态,“准备”的主要作用就是通过回滚未提交的事务及同步已提交的事务至数据文件也使得数据文件处于一致性状态。在准备过程结束后,Innodb表数据已经前滚到整个备份结束的点,而不是回滚到xtrabackup刚开始的点。

通过--apply-log选项可用于实现上述功能,命令如下:

[ ~]# innobackupex --apply-log /opt/mysqlbackup/full/2020-01-17_10-39-52/
[ 2020-01-17_10-39-52]# cat xtrabackup_checkpoints 
backup_type = full-prepared   #当准备工作完成后,备份目录下的此文件内容中的备份类型会为:full-prepared
from_lsn = 0
to_lsn = 2841752
last_lsn = 2841761
compact = 0
recover_binlog_info = 0
flushed_lsn = 2841761

注:/opt/mysqlbackup/full/2020-01-17_10-39-52/是备份文件所在目录名称,如果执行正确,最后几行输出的信息如下:

使用xtrabackup备份MySQL数据库

在实现“准备”的过程中,innobackupex通常还可以使用“--user-memory”选项来指定其可以使用的内存大小,默认为100M,如果有足够的内存,可以多划分一些内存给prepare的过程,以提高其完成速度。

在准备工作完成后,即可使用以下命令进行恢复:

[ ~]# innobackupex --copy-back /opt/mysqlbackup/full/2020-01-17_10-39-52/

确认数据已恢复:

使用xtrabackup备份MySQL数据库

完全备份的数据已经恢复,但是需要注意权限的问题,恢复后的数据属主及属组都是当前用户root,所以还需要更改其属主及属组,如下:

[ ~]# cd /usr/local/mysql/data/
[ data]# chown -R mysql.mysql .
[ data]# ll        #确认当前属组与属主
总用量 122924
drwxr-x--- 2 mysql mysql       90 1月  17 11:15 data1
-rw-r----- 1 mysql mysql      324 1月  17 11:15 ib_buffer_pool
-rw-r----- 1 mysql mysql 12582912 1月  17 11:15 ibdata1
-rw-r----- 1 mysql mysql 50331648 1月  17 11:15 ib_logfile0
-rw-r----- 1 mysql mysql 50331648 1月  17 11:15 ib_logfile1
-rw-r----- 1 mysql mysql 12582912 1月  17 11:15 ibtmp1
drwxr-x--- 2 mysql mysql     4096 1月  17 11:15 mysql
drwxr-x--- 2 mysql mysql     8192 1月  17 11:15 performance_schema
drwxr-x--- 2 mysql mysql     8192 1月  17 11:15 sys
-rw-r----- 1 mysql mysql       20 1月  17 11:15 xtrabackup_binlog_pos_innodb
-rw-r----- 1 mysql mysql      481 1月  17 11:15 xtrabackup_info
-rw-r----- 1 mysql mysql        1 1月  17 11:15 xtrabackup_master_key_id
[ ~]# systemctl restart mysqld   #在数据恢复后,需要重启服务器,否则数据不统一

7、查看数据库中恢复后的数据

[ ~]# mysql -uroot -p123.com -e "select * from data1.t1;"

+------+------+
| id   | name |
+------+------+
|    1 | tom1 |
|    2 | tom2 |
|    3 | tom3 |
+------+------+

8、还原增量备份

为了防止还原时产生大量的二进制日志,在还原时最好临时关闭二进制日志,如下:

[ ~]# mysql -uroot -p123.com -e ‘set sql_log_bin=0;‘    #临时关闭二进制日志
[ ~]# mysql -uroot -p123.com < /opt/mysqlbackup/inc/2020-01-17.sql
#恢复二进制日志
[ ~]# mysql -uroot -p123.com -e ‘set sql_log_bin=1;‘  #开启二进制日志
[ ~]# mysql -uroot -p123.com -e "select * from data1.t1;"
#确认数据恢复正确

+------+------+
| id   | name |
+------+------+
|    1 | tom1 |
|    2 | tom2 |
|    3 | tom3 |
|    4 | tom4 |
|    5 | tom5 |
+------+------+--+i

三、xtrabackup完全备份+xtrabackup增量备份

在第一个备份方案中,增量备份使用的是备份二进制日志,其实xtrabackup还支持进行增量备份,xtrabackup的备份原理如下:

在innodb内部会维护一个redo日志我呢见,也可以叫做事务日志文件(transaction,事务日志),事务日志会存储每个innodb表数据的记录修改,当innodb启动时,innodb会检查数据文件和事务日志,并能执行两个步骤:它应用已经提交的事务日志到数据文件,并将修改过但没有提交的数据进行回滚操作。xtrabackup在启动时会记住log sequence number(LSN),并且复制所有的数据文件,复制过程需要一些时间,所以这期间如果数据文件有改动,那么将会使数据库处于一个不同的时间点。这时,xtrabackup会运行一个后台进程,用于监视事务日志,并从事务日志复制最新的修改,xtrabackup必须持续的做这个操作,是因为事务日志是会轮转重复的写入,并且事务日志可以被重用。所以xtrabackup自启动开始,就不停的将事务日志中每个数据文件的修改都记录下来。这就是xtrabackup的备份过程。

所以每个innodb的页面都会包含一个LSN信息,每当相关的数据发生改变,相关的页面LSN就会自动增长。这就是innodb表可以进行增量备份的基础。xtrabackup基于innodb的crash-recovery功能,它会复制innodb的data file ,由于不锁表,复制出来的数据是不一致的,在恢复的时候使用crash-recovery,使得数据恢复一致。

1、创建一个测试库,并准备一张表插入几行数据

mysql> create database test;
mysql> use test;
mysql> create table xx(id int,name varchar(20));
mysql> insert into xx values(1,‘tom1‘);
mysql> insert into xx values(2,‘tom2‘);
mysql> select * from xx;
+------+------+
| id   | name |
+------+------+
|    1 | tom1 |
|    2 | tom2 |
+------+------+

2、xtrabackup进行完全备份

[ ~]# xtrabackup --defaults-file=/etc/my.cnf --user=bakuser --password="123.com" --port=3306 --backup --target-dir=/opt/mysqlbackup/full/full_incre_$(date ‘+%F_%T‘)

上述各个指令解释如下:

  • --defaults-file:指定数据库的配置文件,如果使用该参数,必须作为第一个参数;
  • --user:指定连接数据库的用户名;
  • --password:指定连接数据库的密码;
  • --port:指定连接数据库的端口号;
  • --backup:实施备份到target-dir;
  • --target-dir=name:备份文件的存放目录路径。innobackupex要从其中获取datadir等信息;
  • --database:指定要备份的数据库,这里指定的数据库只对myisam和innodb表的表结构有效,对于innodb数据库来说都是完全备份(恢复时也一样)。

3、查看完全备份文件

使用xtrabackup备份MySQL数据库

4、进行第一次增量备份

#先插入新的数据
[ full]# mysql -uroot -p123.com -e "insert into test.xx values(3,‘tom3‘);"
#再进行增量备份
[ full]# xtrabackup --defaults-file=/etc/my.cnf --user=bakuser --password="123.com" --port=3306 --backup --target-dir=/opt/mysqlbackup/inc/incre_$(date ‘+%F_%T‘) --incremental-basedir=/opt/mysqlbackup/full/full_incre_2020-01-17_14\:34\:39/

在上述指令中,--incremental-basedir是指定上次完整备份或者增量备份文件的位置(即如果是第一次增量备份则指向完全备份所在目录,在执行过增量备份之后再一次进行增量备份时,其--incremental-basedir应该指向上一次的增量备份所在的目录)。

查看增量备份文件:

[ full]# ll /opt/mysqlbackup/inc/
总用量 0
drwxr-x--- 7 root root 274 1月  17 15:12 incre_2020-01-17_15:12:00
# 注:这里的增量备份只是针对innodb,对于myisam来说,还是完整备份。

5、进行第二次增量备份

#再插入新的数据
[ full]# mysql -uroot -p123.com -e "insert into test.xx values(4,‘tom4‘);"
#进行第二次增量备份
[ full]# xtrabackup --defaults-file=/etc/my.cnf --user=bakuser --password="123.com" --port=3306 --backup --target-dir=/opt/mysqlbackup/inc/incre_$(date ‘+%F_%T‘) --incremental-basedir=/opt/mysqlbackup/inc/incre_2020-01-17_15\:12\:00/

注:第二次增量备份--incremental-basedir应该指向上一次增量备份文件的位置。

6、恢复完全备份以及增量备份

恢复数据的大概流程如下:

如果备份文件是tar包,解包命令为:tar -izxf xxx.tar,这里必须使用-i参数,表示忽略存档中的0字节。
首先准备恢复完全备份:

[ ~]# xtrabackup --defaults-file=/etc/my.cnf --prepare --user=bakuser --password="123.com" --apply-log-only --target-dir=/opt/mysqlbackup/full/full_incre_2020-01-17_14\:34\:39/

再准备恢复到第一次增量备份的时刻,如下:

[ ~]# xtrabackup  --defaults-file=/etc/my.cnf --prepare --user=bakuser --password=‘123.com‘ --apply-log-only --target-dir=/opt/mysqlbackup/full/full_incre_2020-01-17_14\:34\:39/ --incremental-dir=/opt/mysqlbackup/inc/incre_2020-01-17_15\:12\:00/

再准备恢复第二次增量备份,如下:

[ ~]# xtrabackup  --defaults-file=/etc/my.cnf --prepare --user=bakuser --password=‘123.com‘ --apply-log-only --target-dir=/opt/mysqlbackup/full/full_incre_2020-01-17_14\:34\:39/ --incremental-dir=/opt/mysqlbackup/inc/incre_2020-01-17_15\:20\:32/

然后停止MySQL数据库:

[ ~]# systemctl stop mysqld

开始rsync数据文件:

[ ~]# cd /opt/mysqlbackup/full/full_incre_2020-01-17_14\:34\:39/
[ full_incre_2020-01-17_14:34:39]# rsync -rvt --exclude ‘xtrabackup_checkpoints‘ --exclude ‘xtrabackup_logfile‘ ./ /usr/local/mysql/data/

当数据恢复到mysql的data目录以后,还需要确保所有数据文件的属主和属组均为正确的用户,如我这里需要修改为mysql,如下:

[ full_incre_2020-01-17_14:34:39]# cd /usr/local/mysql/data/
[ data]# chown -R mysql.mysql .
#更改恢复后的数据属组和属主为mysql

确认数据已恢复:

[ data]# mysql -uroot -p123.com -e  "select * from test.xx;"
+------+------+
| id   | name |
+------+------+
|    1 | tom1 |
|    2 | tom2 |
|    3 | tom3 |
|    4 | tom4 |
+------+------+

四、innobackupex全库备份+innobackupex增量备份

1、全库备份

#准备测试数据
[ data]# mysql -uroot -p123.com -e  "select * from test.xx;"
+------+------+
| id   | name |
+------+------+
|    1 | tom1 |
|    2 | tom2 |
|    3 | tom3 |
+------+------+
#开始完全备份
[ ~]# innobackupex --defaults-file=/etc/my.cnf --user=bakuser --password=‘123.com‘ /opt/mysqlbackup/full/full_incre_$(date ‘+%F_%H%M%S‘) --no-timestamp

注:--no-timestamp选项来阻止命令自动创建一个以时间命名的目录,然后即可自定义目录了;

2、做一次增量备份

# 插入测试数据
[ ~]# mysql -uroot -p123.com -e  "insert into xx values(4,‘tom4‘),(5,‘tom5‘);" test
#进行增量备份
[ ~]# innobackupex --incremental /opt/mysqlbackup/inc/incre_$(date +%Y%m%d_%H%M%S) --incremental-basedir=/opt/mysqlbackup/full/full_incre_2020-01-17_165254/ --user=bakuser --password=‘123.com‘ --no-timestamp
#  --incremental-basedir:指定的是上次完全备份或者增量备份的目录
#由于这是第一次增量备份,所以就需要指定上次完全备份的目录

[ ~]# ll /opt/mysqlbackup/inc/     #查看增量备份文件
总用量 0
drwxr-x--- 7 root root 274 1月  17 17:04 incre_20200117_170424

3、做第二次增量备份

#插入新的数据
[ ~]# mysql -uroot -p123.com -e  "insert into test.xx values(6,‘tom6‘)";
#基于第一次增量备份的目录文件做第二次增量备份
[ ~]# innobackupex --incremental /opt/mysqlbackup/inc/incre_$(date +%Y%m%d_%H%M%S) --incremental-basedir=/opt/mysqlbackup/inc/incre_20200117_170424/ --user=bakuser --password=‘123.com‘ --no-timestamp

4、查看增量备份文件

[ ~]# ll /opt/mysqlbackup/inc/
总用量 0
drwxr-x--- 7 root root 274 1月  17 17:04 incre_20200117_170424
drwxr-x--- 7 root root 274 1月  17 17:10 incre_20200117_171035

5、删除数据文件,准备进行恢复

[ ~]# rm -rf /usr/local/mysql/data/*
#恢复完全备份目录文件
[ ~]# innobackupex --apply-log --redo-only /opt/mysqlbackup/full/full_incre_2020-01-17_165254/
# 将第一次增量备份合并到全备目录
[ ~]# innobackupex --apply-log --redo-only /opt/mysqlbackup/full/full_incre_2020-01-17_165254/ --incremental-dir=/opt/mysqlbackup/inc/incre_20200117_170424/
# 将第二次增量备份合并到全备目录
[ ~]# innobackupex --apply-log --redo-only /opt/mysqlbackup/full/full_incre_2020-01-17_165254/ --incremental-dir=/opt/mysqlbackup/inc/incre_20200117_171035/

6、恢复数据库

[ ~]# systemctl stop mysqld    #停止数据库
#进行恢复
[ ~]# innobackupex --defaults-file=/etc/my.cnf --user=bakuser --password=‘123.com‘ --copy-back  /opt/mysqlbackup/full/full_incre_2020-01-17_165254/

7、修改恢复后的文件属主及属组

[ ~]# cd /usr/local/mysql/data/
[ data]# chown -R mysql.mysql .

8、启动MySQL数据库,确认数据已恢复

[ data]# systemctl start mysqld
[ data]# mysql -uroot -p123.com -e "select * from test.xx;"

+------+------+
| id   | name |
+------+------+
|    1 | tom1 |
|    2 | tom2 |
|    3 | tom3 |
|    4 | tom4 |
|    5 | tom5 |
|    6 | tom6 |
+------+------+

数据恢复成功。

五、附加——Xtrabackup的“流”及“备份压缩”功能

Xtrabackup对备份的数据文件支持“流”功能,即可以将备份的数据通过STDOUT传输给tar程序进行归档,而不是默认的直接保存至某备份目录中。要使用此功能,仅需要使用--stream选项即可。如下:

#进行完整备份
[ opt]# innobackupex --user=bakuser --password="123.com" --stream=tar /opt/mysqlbackup/full/ | gzip > /opt/mysqlbackup/full/full_`date +%F_%H%M%S`.tar.gz
#上述命令生成的备份文件如下:
[ full]# ll /opt/mysqlbackup/full/
总用量 640
-rw-r--r-- 1 root root 652578 1月  17 17:45 full_2020-01-17_174513.tar.gz

———————— 本文至此结束,感谢阅读 ————————

相关推荐