使用mysqldump进行数据库或表的备份非常方便,操作简单使用灵活,在小数据量的备份和恢复时间可以接受,如果数据量较大,mysqldump恢复的时间会很长而难以接受。
xtrabackup是一款高效的备份工具,备份时并不会影响原数据库的正常更新。
xtrabackup安装
官方网站:https://www.percona.com wget https://www.percona.com/downloads/XtraBackup/Percona-XtraBackup-2.4.4/binary/redhat/7/x86_64/percona-xtrabackup-24-2.4.4-1.el7.x86_64.rpm wget https://www.percona.com/downloads/percona-toolkit/2.2.19/RPM/percona-toolkit-2.2.19-1.noarch.rpm yum install ./*.rpm #使用yum自动解决依赖包
备份的实现
-------------------------------------------------------------------------【完全备份】-------------------------------------------------------------------------
# innobackupex --user=DBUSER --password=DBUSERPASS /path/to/BACKUP-DIR/
如果要使用一个最小权限的用户进行备份,则可基于如下命令创建此类用户
mysql> GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO ’bkpuser’@’localhost’; mysql> FLUSH PRIVILEGES;
开启二进制日志,并指定保存路径
#vim /etc/my.cnf [mysqld] log-bin=/data/mysqlbinlog/mysql-bin.log #mkdir /data/mysqlbinlog #chown -R mysql.mysql /data/mysqlbinlog #systemctl restart mariadb
创建备份文件所在目录然后备份
#mkdir /mybackups
#innobackupex --user=root --password=123456 /mybackups/
...
160817 11:52:07 Executing UNLOCK TABLES
160817 11:52:07 All tables unlocked
160817 11:52:07 Backup created in directory \'/mybackups/2016-08-17_11-51-57\'
MySQL binlog position: filename \'mysql-bin.000001\', position \'245\'
160817 11:52:07 [00] Writing backup-my.cnf
160817 11:52:07 [00] ...done
160817 11:52:07 [00] Writing xtrabackup_info
160817 11:52:07 [00] ...done
xtrabackup: Transaction log of lsn (1837553) to (1837553) was copied.
160817 11:52:07 completed OK!
备份完成之后查看备份目录
# ls /mybackups/
2016-08-17_11-51-57
# cd 2016-08-17_11-51-57/;ls
backup-my.cnf mydb performance_schema xtrabackup_binlog_info xtrabackup_info
ibdata1
模拟丢失数据
删除数据目录
#systemctl stop mariadb
#cd /var/lib/mysql/
#rm -rf ./
准备一个完全备份
#innobackupex --apply-log /path/to/BACKUP-DIR
一般情况下,在备份完成后,数据尚且不能用于恢复操作,因为备份的数据可能包含尚未提交的事务或者已经提交但尚未同步至数据文件中的事务。
因此,此时数据文件仍处于不一致的状态。"准备"的主要作用正是通过回滚未提交的事务及同步已经提交的事务至数据文件也使得数据文件处于一致性状态
只要当我们需要开始还原的时候才"准备"
#innobackupex --apply-log /mybackups/2016-08-17_11-51-57
...
InnoDB: Setting file \'./ibtmp1\' size to 12 MB. Physically writing the file full; Please wait ...
InnoDB: File \'./ibtmp1\' size is now 12 MB.
InnoDB: 96 redo rollback segment(s) found. 1 redo rollback segment(s) are active.
InnoDB: 32 non-redo rollback segment(s) are active.
InnoDB: Waiting for purge to start
InnoDB: 5.7.13 started; log sequence number 1838101
xtrabackup: starting shutdown with innodb_fast_shutdown = 1
InnoDB: FTS optimize thread exiting.
InnoDB: Starting shutdown...
InnoDB: Shutdown completed; log sequence number 1838120
160817 12:47:42 completed OK!
从一个完全备份中恢复数据
#innobackupex --copy-back /path/to/BACKUP-DIR
注意:恢复不用启动MySQL
#innobackupex --copy-back /mybackups/2016-08-17_11-51-57/
...
160817 13:11:29 [01] ...done
160817 13:11:29 [01] Copying ./school/teacher.frm to /var/lib/mysql/school/teacher.frm
160817 13:11:29 [01] ...done
160817 13:11:29 [01] Copying ./xtrabackup_info to /var/lib/mysql/xtrabackup_info
160817 13:11:29 [01] ...done
160817 13:11:29 [01] Copying ./ibtmp1 to /var/lib/mysql/ibtmp1
160817 13:11:29 [01] ...done
160817 13:11:29 completed OK!
还原成功后,检查并启动数据库
查看MySQL数据目录,已经恢复回来了
#ls /var/lib/mysql/
ibdata1 ib_logfile0 ib_logfile1 ibtmp1 mydb mysql performance_schema school xtrabackup_info
当数据恢复至DATADIR目录以后,还需要确保所有数据文件的属主和属组均为正确的用户,如mysql,否则,在启动mysqld之前还需要事先修改数据文件的属主和属组。如:
chown -R mysql.mysql /var/lib/mysql/
启动数据库,检查数据
# systemctl start mariadb
-------------------------------------------------------------------------【增量备份】-------------------------------------------------------------------------
创建一个新的完全备份
# innobackupex --user=root --password=123456 /mybackups/ # ls /mybackups/ 2016-08-17_11-51-57(上次的wan完全备份,磁盘空间够用的话可以留着,否则可以删除) 2016-08-17_15-43-49(最新的完全备份)
查看备份点
# cat /mybackups/2016-08-17_15-43-49/xtrabackup_checkpoints
backup_type = full-backuped
from_lsn = 0
to_lsn = 1838120
last_lsn = 1838120
compact = 0
recover_binlog_info = 0
在库里写入新的数据
# mysql -uroot -p123456
MariaDB [(none)]> use school
MariaDB [school]> create table t1(id int);
MariaDB [school]> insert into t1 value(1),(2);
MariaDB [school]> \q
数据有变动了,现在做增量备份
每个InnoDB的页面都会包含一个LSN信息,每当相关的数据发生改变,相关的页面的LSN就会自动增长。这正是InnoDB表可以进行增量备份的基础。
即innobackupex通过备份上次完全备份之后发生改变的页面来实现。
# innobackupex --incremental /backup --incremental-basedir=BASEDIR
其中,BASEDIR指的是完全备份所在的目录,此命令执行结束后,innobackupex命令会在/backup目录中创建一个新的以时间命名的目录以存放所有的增量备份数据。
另外,在执行过增量备份之后再一次进行增量备份时,其--incremental-basedir应该指向上一次的增量备份所在的目录。
需要注意的是,增量备份仅能应用于InnoDB或XtraDB表,对于MyISAM表而言,执行增量备份时其实进行的是完全备份。
# innobackupex --user=root --password=123456 --incremental /mybackups/ --incremental-basedir=/mybackups/2016-08-17_15-43-49/ 查看备份目录 # ls /mybackups/ 2016-08-17_11-51-57 2016-08-17_15-43-49 2016-08-17_16-04-43(增量备份)
查看备份点
# cat /mybackups/2016-08-17_16-04-43/xtrabackup_checkpoints
backup_type = incremental
from_lsn = 1838120 <--------可以看到是从上次完整备份的结束点开始
to_lsn = 1840190
last_lsn = 1840190
compact = 0
recover_binlog_info = 0
再次写入新的数据
MariaDB [(none)]> create database sellsa;
MariaDB [(none)]> use sellsa;
MariaDB [sellsa]> create table test1(Name char(10));
再做一次增量备份
# innobackupex --user=root --password=123456 --incremental /mybackups/ --incremental-basedir=/mybackups/2016-08-17_16-04-43/(上次增量备份的目录) # ls /mybackups/ 2016-08-17_11-51-57 2016-08-17_15-43-49 2016-08-17_16-04-43(增量备份) 2016-08-17_16-14-01(增量备份)
查看备份点
# cat /mybackups/2016-08-17_16-14-01/xtrabackup_checkpoints
backup_type = incremental
from_lsn = 1840190 <--------可以看到是从上次增量备份的结束点开始
to_lsn = 1841816
last_lsn = 1841816
compact = 0
recover_binlog_info = 0
当我们再次写入数据,然后没来得及做增量备份,数据库没了,此刻该怎么办?
再次写入数据
MariaDB [(none)]> use school;
MariaDB [school]> insert into t1 values(3),(4);
假如现在数据库崩溃了或者磁盘坏掉了,没有来得及做增量备份,我们现在模拟把数据目录清掉
# systemctl stop mariadb
# cd /var/lib/mysql/
# rm -rf ./*
***************************************************************************************************
"准备"增量备份与准备完全备份有着一些不同,尤其要注意的是:
1)需要在每个备份(包括完全和各个增量备份)上,将已经提交的事务进行"重放",所有的备份数据将合并到完全备份上
2)基于所有的备份将未提交的事务进行"回滚"
于是,操作就变成了:
# innobackupex --apply-log --redo-only BASE-DIR(完全备份所在目录)
接着执行一个增量备份:
# innobackupex --apply-log --redo-only BASE-DIR --incremental-dir=INCREMENTAL-DIR-1(第一次增量备份所在目录)
而后是第二个增量:
# innobackupex --apply-log --redo-only BASE-DIR --incremental-dir=INCREMENTAL-DIR-2(第二次增量备份所在目录)
以此类推
***************************************************************************************************
# innobackupex --apply-log --redo-only /mybackups/2016-08-17_15-43-49/ # innobackupex --apply-log --redo-only /mybackups/2016-08-17_15-43-49/ --incremental-dir=/mybackups/2016-08-17_16-04-43/ # innobackupex --apply-log --redo-only /mybackups/2016-08-17_15-43-49/ --incremental-dir=/mybackups/2016-08-17_16-14-01/
我们去查看合并后的备份点
# cat /mybackups/2016-08-17_16-14-01/xtrabackup_checkpoints
backup_type = incremental
from_lsn = 1840190 <-----------
to_lsn = 1841816
last_lsn = 1841816
compact = 0
recover_binlog_info = 0
现在我们还原这个合并后的完全备份
# innobackupex --copy-back /mybackups/2016-08-17_15-43-49/ 更改属主、属组 # chown -R mysql.mysql /var/lib/mysql/
因为最后没有增量备份,所以我们需要用到二进制日志及时点恢复
查看最后一次增量备份的二进制日志位置点信息 # cat /mybackups/2016-08-17_16-14-01/xtrabackup_binlog_info mysql-bin.000005 707 把这个点以后的二进制日志导出来 # mysqlbinlog --start-position=707 /data/mysqlbinlog/mysql-bin.000005 >/tmp/inc.sql 启动数据库 # systemctl start mariadb #进入MySQL,设置这个会话不记录二进制日志 MariaDB [(none)]> set session sql_log_bin=0; 导入刚刚的日志文件 MariaDB [(none)]> source /tmp/inc.sql; #设置会记录二进制日志 MariaDB [school]> set session sql_log_bin=1;
-------------------------------------------------------------------------【导入或导出单张表】-------------------------------------------------------------------------
默认情况下,InnoDB表不能通过直接复制表文件的方式在mysql服务器之间进行移植,即便使用了innodb_file_per_table选项。而使用Xtrabackup工具可以实现此种功能,不过,此时需要“导出”表的mysql服务器启用了innodb_file_per_table选项(严格来说,是要“导出”的表在其创建之前,mysql服务器就启用了innodb_file_per_table选项),并且“导入”表的服务器同时启用了innodb_file_per_table和innodb_expand_import选项。
(1)“导出”表
导出表是在备份的prepare阶段进行的,因此,一旦完全备份完成,就可以在prepare过程中通过--export选项将某表导出了:
# innobackupex --apply-log --export /path/to/backup
此命令会为每个innodb表的表空间创建一个以.exp结尾的文件,这些以.exp结尾的文件则可以用于导入至其它服务器。(拷贝完,注意文件的权限,否则导入表的时候会失败)
(2)“导入”表
要在mysql服务器上导入来自于其它服务器的某innodb表,需要先在当前服务器上创建一个跟原表表结构一致的表,而后才能实现将表导入:
mysql> CREATE TABLE mytable (...) ENGINE=InnoDB;
然后将此表的表空间删除:
mysql> ALTER TABLE mydatabase.mytable DISCARD TABLESPACE;
接下来,将来自于“导出”表的服务器的mytable表的mytable.ibd和mytable.exp文件复制到当前服务器的数据目录,然后使用如下命令将其“导入”:
mysql> ALTER TABLE mydatabase.mytable IMPORT TABLESPACE;
-------------------------------------------------------------------------【使用Xtrabackup对数据库进行部分备份】-------------------------------------------------------------------------
Xtrabackup也可以实现部分备份,即只备份某个或某些指定的数据库或某数据库中的某个或某些表。但要使用此功能,必须启用innodb_file_per_table选项,即每张表保存为一个独立的文件。同时,其也不支持--stream选项,即不支持将数据通过管道传输给其它程序进行处理。
此外,还原部分备份跟还原全部数据的备份也有所不同,即你不能通过简单地将prepared的部分备份使用--copy-back选项直接复制回数据目录,而是要通过导入表的方向来实现还原。当然,有些情况下,部分备份也可以直接通过--copy-back进行还原,但这种方式还原而来的数据多数会产生数据不一致的问题,因此,无论如何不推荐使用这种方式。
(1)创建部分备份
创建部分备份的方式有三种:正则表达式(--include), 枚举表文件(--tables-file)和列出要备份的数据库(--databases)。
(a)使用--include
使用--include时,要求为其指定要备份的表的完整名称,即形如databasename.tablename,如:
# innobackupex --include=\'^mageedu[.]tb1\' /path/to/backup
(b)使用--tables-file
此选项的参数需要是一个文件名,此文件中每行包含一个要备份的表的完整名称;如:
# echo -e \'mageedu.tb1\nmageedu.tb2\' > /tmp/tables.txt # innobackupex --tables-file=/tmp/tables.txt /path/to/backup
(c)使用--databases
此选项接受的参数为数据名,如果要指定多个数据库,彼此间需要以空格隔开;同时,在指定某数据库时,也可以只指定其中的某张表。此外,此选项也可以接受一个文件为参数,文件中每一行为一个要备份的对象。如:
# innobackupex --databases="mageedu testdb" /path/to/backup
(2)整理(preparing)部分备份
prepare部分备份的过程类似于导出表的过程,要使用--export选项进行:
# innobackupex --apply-log --export /pat/to/partial/backup
此命令执行过程中,innobackupex会调用xtrabackup命令从数据字典中移除缺失的表,因此,会显示出许多关于“表不存在”类的警告信息。同时,也会显示出为备份文件中存在的表创建.exp文件的相关信息。
(3)还原部分备份
还原部分备份的过程跟导入表的过程相同。当然,也可以通过直接复制prepared状态的备份直接至数据目录中实现还原,不要此时要求数据目录处于一致状态。