xtrabackup8:无全局锁备份原理浅析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了xtrabackup8:无全局锁备份原理浅析相关的知识,希望对你有一定的参考价值。
参考技术A https://mp.weixin.qq.com/s/vl9RscCswHhl2D2jsj15EQ众所周知,xtrabackup2.4 备份 mysql5.7 时,在备份完 InnoDB 表后,会加全局锁 FTWRL(即:flush tables with read lock),然后做以下关键操作:
做完这些后,就会解锁,基本上备份也就结束了。xtrabackup 备份的数据在恢复时需要应用 redo log 前滚到一个位置,这个位置就是刚提到的 redo log LSN,让数据最终处于一个一致性快照中;并且这个数据还需要与binlog position、GTID一致,因为后续可能还需要基于 binlog 做增量恢复或者复制(这就需要 binlog position、GTID 作为起始位置)。
FTWRL 是这样来保证上述一致性的:
然后在备份恢复阶段(--apply-log),redo log 重做的截止位置就是 FTWRL 期间获取到的 LSN( xtrabackup_checkpoints 文件中的 last_lsn):
xtrabackup8 适用于 MySQL8.0,因为 MySQL8.0 中的系统表不再使用 MyISAM 引擎,因此这成了一个去掉 FTWRL 重要前提。那去掉 FTWRL 后如何保证上文提到的一致性问题呢?
此处得展开说下二阶段提交内部各个阶段的锁:
而MySQL8所有版本(目前最新8.0.28)由于 bug,查询 log_status 表时只获取 LOCK_log、global_sid_lock 锁。因此 InnoDB 内部可能存在事务已完成 sync ,但未完成 commit,即:
查询到的 gtid_executed 实际落后于数据和 binlog position。
bug 详见:
https://bugs.mysql.com/bug.php?id=102175
https://jira.percona.com/browse/PS-7873
修复方法:查询 log_status 表时,同时获取 LOCK_log 、LOCK_sync、LOCK_commit、global_sid_lock,这将和事务提交的各阶段锁都互斥,保证读到的 GTID 与 binlog position 一致。
上面好像忘了提获取 LSN 由什么锁保护了,除了上述锁,还有 log_buffer_x_lock_enter、log_t::checkpointer_mutex,分别阻塞修改数据的DML操作和 checkpoint。也就是说查询 log_status 表时:
这样能保证备份数据的一致性,数据(即LSN)与 binlog position、GTID的一致性。
使用 xtrabackup 进行MySQL数据库物理备份
0. xtrabackup的功能
能实现的功能:
非阻塞备份innodb等事务引擎数据库、
备份myisam表会阻塞(需要锁)、
支持全备、增量备份、压缩备份、
快速增量备份(xtradb,原理类似于oracle:tracking 上次备份之后发生修改的page.)、
percona支持归档redo log的备份、
percona5.6+支持轻量级的backup-lock替代原来重量级的FTWRL,此时即使备份非事务引擎表也不会阻塞innodb的DML语句了、
支持加密备份、流备份(备份到远程机器)、并行本地备份、并行压缩、并行加密、并行应用备份期间产生的redo日志、并行copy-back
支持部分备份,只备份某个库,某个表
支持部分恢复
支持备份单个表分区
支持备份速度限制,指备份产生的IO速度的限制
支持point-in-time恢复
支持compat备份,也即使不备份索引数据,索引在prepare时--rebuild-indexs
支持备份buffer pool
支持单表export, import到其它库
支持 rsync 来缩短备份非事务引擎表的锁定时间
1. 物理备份需要的权限
使用innobackupex/xtrabackup进行备份,必须先配置好权限。需要的权限分为两部分:
1>系统层面的权限: 执行 innobackupex/xtrabackup 命令的Linux用户需要对mysql datadir和保存备份的目录有读写执行的权限,当然需要对这些命令要有执行权限;
2>mysqld层面的权限:innobackupex/xtrabackup --user=bkpuser 该用户bkpuser是指mysql.user表中的用户,不是系统层面的用户;需要一些基本的权限来执行备份过程:
最基本的权限:
create user ‘bkpuser‘@‘localhost‘ identified by ‘xxx‘;
grant reload,lock tables,replication client on *.* to ‘bkpuser‘@‘localhost‘;
这些权限仅仅只能完成:全备,增量备份,恢复;
一般如果需要部分备份,export表,import表,还需要:grant create tablespace on *.* to ‘bkpuser‘@‘localhost‘;
如果还需要对备份的过程中对锁进行一些优化,防止发生阻塞所有DML的情况,则还需要:
grant process,super on *.* to ‘bkpuser‘@‘localhost‘;
([email protected])[(none)]mysql>show grants for ‘bkpuser‘@‘localhost‘G *************************** 1. row *************************** Grants for [email protected]: GRANT RELOAD, PROCESS, SUPER, LOCK TABLES, REPLICATION CLIENT, CREATE TABLESPACE ON *.* TO ‘bkpuser‘@‘localhost‘ IDENTIFIED BY PASSWORD ‘*BDC62F68AF8F0B8BFAE27FF782C5D8CE9F4BAFCB‘ 1 row in set (0.00 sec)
2. innobackupex 命令选项:
innobackupex --help
3. 使用 innobackupex 备份
3.1 全备
(这里系统层面使用的root用户备份,msyql层面使用的是bkpuser用户,root需要对datadir /var/lib/mysql, 备份目录/backup/xtrabackup/full有读写执行权限;bkpuser也需在mysql中有相关权限)
[[email protected] ~]# innobackupex /backup/xtrabackup/full --user=bkpuser --password=digdeep
View Code
3.2 恢复
1> 第一步prepare(两次prepare,第一次应用备份期间产生的redo log,进行前滚和回滚:replay在redo log中已经提交的事务,rollback没有提交的事务)
注意这里的路径,必须要包括最后那个timestamp目录,不然会下面的错误:
[[email protected] ~]# innobackupex --apply-log /backup/xtrabackup/full/ --user=bkpuser --password=digdeep 151106 10:41:48 innobackupex: Starting the apply-log operation IMPORTANT: Please check that the apply-log run completes successfully. At the end of a successful apply-log run innobackupex prints "completed OK!". innobackupex version 2.3.2 based on MySQL server 5.6.24 Linux (i686) (revision id: 306a2e0) xtrabackup: cd to /backup/xtrabackup/full xtrabackup: Error: cannot open ./xtrabackup_checkpoints xtrabackup: error: xtrabackup_read_metadata() xtrabackup: This target seems not to have correct metadata... 2015-11-06 10:41:48 b771e6d0 InnoDB: Operating system error number 2 in a file operation. InnoDB: The error means the system cannot find the path specified. xtrabackup: Warning: cannot open ./xtrabackup_logfile. will try to find. 2015-11-06 10:41:48 b771e6d0 InnoDB: Operating system error number 2 in a file operation. InnoDB: The error means the system cannot find the path specified. xtrabackup: Fatal error: cannot find ./xtrabackup_logfile. xtrabackup: Error: xtrabackup_init_temp_log() failed.
--apply-log会调用 xtrabackup --prepare两次,第一次前滚和回滚,第二次生成iblogfile[0|1]
[[email protected] ~]# innobackupex --apply-log /backup/xtrabackup/full/2015-11-05_22-38-55/ --user=bkpuser --password=digdeep
View Code
3.3 恢复 --copy-back
直接将上面prepare好的所有文件,复制到mysqld的datadir目录(会读取my.cnf中的配置信息)。
--copy--back的注意事项:
1> datadir必须是空的,或者使用--force-non-empty-directories选项;
2> mysqld必须关闭,如果是--import部分恢复,则不能关闭;
3> --copy-back完成之后,需要修改datadir目录下的文件权限: chown -R mysql:mysql /var/lib/mysql
[[email protected] ~]# mysqladmin -uroot -pxxx shutdown (关闭mysqld)
[[email protected] ~]# cd /var/lib/mysql
[[email protected] mysql]# ls
aazj ib_logfile1 mysql-bin.000003 mysql-bin.000008 mysql-bin.000013 performance_schema
auto.cnf localhost-slow.log mysql-bin.000004 mysql-bin.000009 mysql-bin.000014 t
general.log mysql mysql-bin.000005 mysql-bin.000010 mysql-bin.000015 xtrabackup_binlog_pos_innodb
ibdata1 mysql-bin.000001 mysql-bin.000006 mysql-bin.000011 mysql-bin.000016 xtrabackup_info
ib_logfile0 mysql-bin.000002 mysql-bin.000007 mysql-bin.000012 mysql-bin.index
[[email protected] mysql]# mv * /backup/xtrabackup/ (进行清空)
[[email protected] mysql]# ls
[[email protected] mysql]# innobackupex --copy-back /backup/xtrabackup/full/2015-11-05_22-38-55/ --user=bkpuser --password=digdeep
[[email protected] mysql]# innobackupex --copy-back /backup/xtrabackup/full/2015-11-05_22-38-55/ --user=bkpuser --password=digdeep 151106 11:07:38 innobackupex: Starting the copy-back operation IMPORTANT: Please check that the copy-back run completes successfully. At the end of a successful copy-back run innobackupex prints "completed OK!". innobackupex version 2.3.2 based on MySQL server 5.6.24 Linux (i686) (revision id: 306a2e0) 151106 11:07:38 [01] Copying ib_logfile0 to /var/lib/mysql/ib_logfile0 151106 11:07:40 [01] ...done 151106 11:07:40 [01] Copying ib_logfile1 to /var/lib/mysql/ib_logfile1 151106 11:07:41 [01] ...done 151106 11:07:41 [01] Copying ibdata1 to /var/lib/mysql/ibdata1 151106 11:07:45 [01] ...done 151106 11:07:45 [01] Copying ./xtrabackup_info to /var/lib/mysql/xtrabackup_info 151106 11:07:45 [01] ...done 151106 11:07:45 [01] Copying ./mysql/slave_master_info.ibd to /var/lib/mysql/mysql/slave_master_info.ibd 151106 11:07:45 [01] ...done [... ...] 151106 11:07:57 [01] Copying ./t/db.opt to /var/lib/mysql/t/db.opt 151106 11:07:57 [01] ...done 151106 11:07:57 [01] Copying ./t/t.frm to /var/lib/mysql/t/t.frm 151106 11:07:57 [01] ...done 151106 11:07:57 completed OK! [[email protected] mysql]# pwd /var/lib/mysql [[email protected] mysql]# ls aazj ibdata1 ib_logfile0 ib_logfile1 mysql performance_schema t xtrabackup_binlog_pos_innodb xtrabackup_info
可以看到恢复之后,没有 binlog 文件盒index文件
启动myqld之前需要修改权限:
[[email protected] mysql]# ls -l total 176164 drwx------ 2 root root 4096 Nov 6 11:07 aazj -rw-rw---- 1 mysql mysql 543 Nov 6 11:13 general.log -rw-r----- 1 root root 79691776 Nov 6 11:07 ibdata1 -rw-r----- 1 root root 50331648 Nov 6 11:07 ib_logfile0 -rw-r----- 1 root root 50331648 Nov 6 11:07 ib_logfile1 -rw-rw---- 1 mysql mysql 543 Nov 6 11:13 localhost-slow.log drwx------ 2 root root 4096 Nov 6 11:07 mysql -rw-rw---- 1 mysql mysql 0 Nov 6 11:12 mysql-bin.index drwx------ 2 root root 4096 Nov 6 11:07 performance_schema drwx------ 2 root root 4096 Nov 6 11:07 t -rw-r----- 1 root root 24 Nov 6 11:07 xtrabackup_binlog_pos_innodb -rw-r----- 1 root root 487 Nov 6 11:07 xtrabackup_info [[email protected] mysql]# chown -R mysql:mysql /var/lib/mysql [[email protected] mysql]# ls -l total 176164 drwx------ 2 mysql mysql 4096 Nov 6 11:07 aazj -rw-rw---- 1 mysql mysql 543 Nov 6 11:13 general.log -rw-r----- 1 mysql mysql 79691776 Nov 6 11:07 ibdata1 -rw-r----- 1 mysql mysql 50331648 Nov 6 11:07 ib_logfile0 -rw-r----- 1 mysql mysql 50331648 Nov 6 11:07 ib_logfile1 -rw-rw---- 1 mysql mysql 543 Nov 6 11:13 localhost-slow.log drwx------ 2 mysql mysql 4096 Nov 6 11:07 mysql -rw-rw---- 1 mysql mysql 0 Nov 6 11:12 mysql-bin.index drwx------ 2 mysql mysql 4096 Nov 6 11:07 performance_schema drwx------ 2 mysql mysql 4096 Nov 6 11:07 t -rw-r----- 1 mysql mysql 24 Nov 6 11:07 xtrabackup_binlog_pos_innodb -rw-r----- 1 mysql mysql 487 Nov 6 11:07 xtrabackup_info
不然启动会在error.log中报错:
2015-11-06 11:13:55 3542 [ERROR] InnoDB: ./ibdata1 can‘t be opened in read-write mode
2015-11-06 11:13:55 3542 [ERROR] InnoDB: The system tablespace must be writable!
2015-11-06 11:13:55 3542 [ERROR] Plugin ‘InnoDB‘ init function returned error.
2015-11-06 11:13:55 3542 [ERROR] Plugin ‘InnoDB‘ registration as a STORAGE ENGINE failed.
2015-11-06 11:13:55 3542 [ERROR] Unknown/unsupported storage engine: InnoDB
2015-11-06 11:13:55 3542 [ERROR] Aborting
启动成功之后,datadir目录下各种文件都产生了:
[[email protected] mysql]# pwd
/var/lib/mysql
[[email protected] mysql]# ls
aazj general.log ib_logfile0 localhost-slow.log mysql-bin.000001 performance_schema xtrabackup_binlog_pos_innodb
auto.cnf ibdata1 ib_logfile1 mysql mysql-bin.index t xtrabackup_info
3.4 innobackupex 增量备份
增量备份之前,必须建立一个全备,第一次增量备份是在全备的基础之上,第二次增量备份是在第一次增量备份的基础之上的,一次类推
全备:
[[email protected] mysql]# innobackupex --user=bkpuser --password=digdeep /backup/xtrabackup/full
[[email protected] mysql]# innobackupex --user=bkpuser --password=digdeep /backup/xtrabackup/full 第一次增量备份: --incremental /backup/xtrabackup/incr1/ 指定增量备份的位置; --incremental-basedir=指定上一次的全备或者增量备份: [[email protected] mysql]# innobackupex --incremental /backup/xtrabackup/incr1/ --incremental-basedir=/backup/xtrabackup/full/2015-11-06_11-29-51/ --user=bkpuser --password=digdeep 151106 11:33:16 innobackupex: Starting the backup operation IMPORTANT: Please check that the backup run completes successfully. At the end of a successful backup run innobackupex prints "completed OK!". 151106 11:33:16 version_check Connecting to MySQL server with DSN ‘dbi:mysql:;mysql_read_default_group=xtrabackup;mysql_socket=/tmp/mysql.sock‘ as ‘bkpuser‘ (using password: YES). 151106 11:33:16 version_check Connected to MySQL server 151106 11:33:16 version_check Executing a version check against the server... 151106 11:33:16 version_check Done. 151106 11:33:16 Connecting to MySQL server host: localhost, user: bkpuser, password: set, port: 0, socket: /tmp/mysql.sock Using server version 5.6.26-log innobackupex version 2.3.2 based on MySQL server 5.6.24 Linux (i686) (revision id: 306a2e0) incremental backup from 731724832 is enabled. xtrabackup: uses posix_fadvise(). xtrabackup: cd to /var/lib/mysql xtrabackup: open files limit requested 0, set to 10240 xtrabackup: using the following InnoDB configuration: xtrabackup: innodb_data_home_dir = ./ xtrabackup: innodb_data_file_path = ibdata1:12M:autoextend xtrabackup: innodb_log_group_home_dir = ./ xtrabackup: innodb_log_files_in_group = 2 xtrabackup: innodb_log_file_size = 50331648 151106 11:33:16 >> log scanned up to (732153217) xtrabackup: Generating a list of tablespaces xtrabackup: using the full scan for incremental backup 151106 11:33:17 [01] Copying ./ibdata1 to /backup/xtrabackup/incr1//2015-11-06_11-33-16/ibdata1.delta 151106 11:33:17 >> log scanned up to (732153217) 151106 11:33:18 [01] ...done 151106 11:33:18 >> log scanned up to (732153217) 151106 11:33:18 [01] Copying ./mysql/slave_master_info.ibd to /backup/xtrabackup/incr1//2015-11-06_11-33-16/mysql/slave_master_info.ibd.delta 151106 11:33:18 [01] ...done 151106 11:33:19 >> log scanned up to (732153217) [... ...] 151106 11:33:30 [01] Copying ./aazj/Configuration.ibd to /backup/xtrabackup/incr1//2015-11-06_11-33-16/aazj/Configuration.ibd.delta 151106 11:33:30 [01] ...done 151106 11:33:31 [01] Copying ./aazj/lx_test.ibd to /backup/xtrabackup/incr1//2015-11-06_11-33-16/aazj/lx_test.ibd.delta 151106 11:33:31 >> log scanned up to (732231774) 151106 11:33:32 [01] ...done 151106 11:33:32 >> log scanned up to (732231774) 151106 11:33:32 [01] Copying ./aazj/Users.ibd to /backup/xtrabackup/incr1//2015-11-06_11-33-16/aazj/Users.ibd.delta 151106 11:33:32 [01] ...done [... ...] 151106 11:33:42 [01] Copying ./aazj/tttt.ibd to /backup/xtrabackup/incr1//2015-11-06_11-33-16/aazj/tttt.ibd.delta 151106 11:33:42 [01] ...done 151106 11:33:42 >> log scanned up to (732501432) 151106 11:33:42 [01] Copying ./aazj/uu_test.ibd to /backup/xtrabackup/incr1//2015-11-06_11-33-16/aazj/uu_test.ibd.delta [... ...] 151106 11:33:47 [01] Copying ./t/t.ibd to /backup/xtrabackup/incr1//2015-11-06_11-33-16/t/t.ibd.delta 151106 11:33:48 [01] ...done 151106 11:33:48 >> log scanned up to (732501432) Executing FLUSH NO_WRITE_TO_BINLOG TABLES... 151106 11:33:48 Executing FLUSH TABLES WITH READ LOCK... 151106 11:33:48 Starting to backup non-InnoDB tables and files 151106 11:33:48 [01] Copying ./mysql/columns_priv.frm to /backup/xtrabackup/incr1//2015-11-06_11-33-16/mysql/columns_priv.frm 151106 11:33:48 [01] ...done [... ...] 151106 11:33:51 [01] Copying ./t/t.frm to /backup/xtrabackup/incr1//2015-11-06_11-33-16/t/t.frm 151106 11:33:51 [01] ...done 151106 11:33:51 Finished backing up non-InnoDB tables and files 151106 11:33:51 [00] Writing xtrabackup_binlog_info 151106 11:33:51 [00] ...done 151106 11:33:51 Executing FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS... xtrabackup: The latest check point (for incremental): ‘732501432‘ xtrabackup: Stopping log copying thread. .151106 11:33:51 >> log scanned up to (732501432) 151106 11:33:51 Executing UNLOCK TABLES 151106 11:33:51 All tables unlocked 151106 11:33:51 Backup created in directory ‘/backup/xtrabackup/incr1//2015-11-06_11-33-16‘ MySQL binlog position: filename ‘mysql-bin.000001‘, position ‘157893‘ 151106 11:33:51 [00] Writing backup-my.cnf 151106 11:33:51 [00] ...done 151106 11:33:51 [00] Writing xtrabackup_info 151106 11:33:51 [00] ...done xtrabackup: Transaction log of lsn (732153217) to (732501432) was copied. 151106 11:33:51 completed OK! [[email protected] mysql]#
第二次增量备份:
[[email protected] mysql]# innobackupex --incremental /backup/xtrabackup/incr2 --incremental-basedir=/backup/xtrabackup/incr1/2015-11-06_11-33-16/ --user=bkpuser --password=digdeep
View Code
3.5 innobackupex 增量备份的恢复
1> 应用全备的redo log:
[[email protected] ~]# innobackupex --apply-log --redo-only /backup/xtrabackup/full/2015-11-06_11-29-51/ --user=bkpuser --password=digdeep
View Code
2> 应用第一次增量备份的redo log:
[[email protected] ~]# innobackupex --apply-log --redo-only /backup/xtrabackup/full/2015-11-06_11-29-51/ --incremental-dir=/backup/xtrabackup/incr1/2015-11-06_11-33-16/ --user=bkpuser --password=digdeep
View Code
3> 应用第二次(最后一次)增量备份的redo log,并且回滚进行崩溃恢复过程(没有--redo-only选项):
[[email protected] ~]# innobackupex --apply-log /backup/xtrabackup/full/2015-11-06_11-29-51/ --incremental-dir=/backup/xtrabackup/incr2/2015-1 1-06_11-43-22/ --user=bkpuser --password=digdeep
View Code
[[email protected] ~]#
然后 --copy-back:
先关闭mysqld: mysqladmin -uroot -pxxx shutdown
[[email protected] mysql]# innobackupex --copy-back /backup/xtrabackup/full/2015-11-06_11-29-51/ --user=bkpuser --password=digdeep
[[email protected] mysql]# innobackupex --copy-back /backup/xtrabackup/full/2015-11-06_11-29-51/ --user=bkpuser --password=digdeep 151106 15:10:23 innobackupex: Starting the copy-back operation IMPORTANT: Please check that the copy-back run completes successfully. At the end of a successful copy-back run innobackupex prints "completed OK!". innobackupex version 2.3.2 based on MySQL server 5.6.24 Linux (i686) (revision id: 306a2e0) 151106 15:10:23 [01] Copying ibdata1 to /var/lib/mysql/ibdata1 151106 15:10:28 [01] ...done 151106 15:10:28 [01] Copying ./xtrabackup_info to /var/lib/mysql/xtrabackup_info 151106 15:10:28 [01] ...done [... ...] 151106 15:10:41 [01] ...done 151106 15:10:41 [01] Copying ./t/db.opt to /var/lib/mysql/t/db.opt 151106 15:10:41 [01] ...done 151106 15:10:41 [01] Copying ./t/t.frm to /var/lib/mysql/t/t.frm 151106 15:10:41 [01] ...done 151106 15:10:42 completed OK!
修改权限:
chown -R mysql:mysql /var/lib/mysql
启动:mysqld_safe --user=mysql &
最后验证还原成功。
4. 部分备份
需要启用 innodb_file_per_table,5.6默认启用。另外在还原时,prepare之后,并不能直接 --copy-back,而只能一个表一个表的import来还原。
[[email protected] xtrabackup]# innobackupex --databases t /backup/xtrabackup/ --user=bkpuser --password=digdeep
View Code
数据库 t 中只有两个表:city, t 都被备份了。
下面我们来看如何还原:
4.1 部分prepare:
[[email protected] xtrabackup]# innobackupex --apply-log --export /backup/xtrabackup/2015-11-06_15-39-34/ --user=bkpuser --password=digdeep
View Code
4.2 下面我们将其 import 到一个新的数据库中:
([email protected])[t]mysql>create database partial;
([email protected])[t]mysql>use partial;
Database changed
([email protected])[partial]mysql>create table city like t.city;
([email protected])[partial]mysql>alter table partial.city discard tablespace;
然后将 city.exp 和 city.ibd 拷贝到 /var/lib/mysql/partial/ 目录下,并修改权限:
[[email protected] t]# cp city.exp city.ibd /var/lib/mysql/partial/
[[email protected] partial]# chown -R mysql:mysql /var/lib/mysql
然后
([email protected])[aazj]mysql>alter table partial.city import tablespace;
Query OK, 0 rows affected, 1 warning (0.11 sec)
([email protected])[aazj]mysql>select count(*) from partial.city;
+----------+
| count(*) |
+----------+
| 3285 |
+----------+
1 row in set (0.01 sec)
可以看到import 成功了。部分恢复成功。
低于t表也同样操作就行了。
([email protected])[partial]mysql>select count(*) from t;
+----------+
| count(*) |
+----------+
| 11 |
+----------+
1 row in set (0.00 sec)
可以看到,这种部分备份/恢复,操作起来比较麻烦,步骤比较多,还需要一个表一个表的处理。对少数表处理还可以,如果很多表,就不方面了。
4.3 部分备份恢复之备份/恢复一个或者多个数据库:
1)备份:
[[email protected] mysql]# innobackupex --database="aazj t mysql information_schema performance_schema" /backup/xtrabackup/partial/ --user=pkpuser --password=digdeep
注意这里 --database = "aazj t mysql performance_schema" 表示指定备份的数据库;还可以增加其他数据库,但是必须使用引号。
2)恢复 prepare:
[[email protected] partial]# innobackupex --apply-log /backup/xtrabackup/partial/2015-11-11_15-22-56 --user=bkpuser --password=digdeep
然后 关闭 mysqld, 清空 datadir :
[[email protected] mysql]# pwd
/var/lib/mysql
/var/lib/mysql
[[email protected] mysql]# rm -rf *
3)copy-back:
[[email protected] partial]# innobackupex --copy-back /backup/xtrabackup/partial/2015-11-11_15-22-56 --user=bkpuser --password=digdeep
然后修改权限:chown -R mysql:mysql /var/lib/mysql
然后启动mysqld,发现数据库 t 被恢复出来了。这里也可以一次备份多个数据库,但是一定要带上 mysql 数据库,不然恢复出来时,没有了数据字典,select读不出数据:
Restoring Partial Backups:
Restoring should be done by restoring individual tables in the partial backup to the server.
It can also be done by copying back the prepared backup to a clean datadir (in that case, make sure to include the mysql database). System database can be created with: $ sudo mysql_install_db --user=mysql (摘自xtrabackup文档)
It can also be done by copying back the prepared backup to a clean datadir (in that case, make sure to include the mysql database). System database can be created with: $ sudo mysql_install_db --user=mysql (摘自xtrabackup文档)
部分恢复一般需要 export, 然后 import. 比较麻烦,但是我们也可以在一个空的 datadir 目录直接 --copy-back,这样的话,那么在备份的时候一定要带上mysql数据库,当然最好带上所有的系统数据库,不然的话,需要使用命令:mysql_install_db --user=mysql --basedir=... 重建那些系统数据库。这就是为什么在部分备份时带上了:mysql performance_schema(information_schema是系统视图,不需要带上,当然带上也是可以的)
4)如果你不想带上 performance_schema(mysql是一定要带上的),那么就必须使用: mysql_install_db --user=mysql --basedir=/usr/local/mysql 来重新生成系统数据库mysql 和 performance_schema。那么此时在 --copy-back之前,必须先删除刚才生成的 和 我们要 --copy-back 重复的文件:
[[email protected] mysql]# rm ibdata1 ib_logfile0 ib_logfile1
[[email protected] mysql]# rm -rf mysql
另外 --copy-back 时要带上参数: --force-non-empty-directories
innobackupex --copy-back --force-non-empty-directories/backup/xtrabackup/partial/2015-11-11_16-17-11/ --user=pkpuser --password=digdeep
因为 datadir 目录非空,所以需要带上该参数:
--force-non-empty-directories
This option, when specified, makes --copy-back or
--move-back transfer files to non-empty directories. Note
that no existing files will be overwritten. If
--copy-back or --nove-back has to copy a file from the
backup directory which already exists in the destination
directory, it will still fail with an error.
即使带上了该参数,如果还存在重名的文件,还是会报错,需要先删除datadir中的重名文件。
This option, when specified, makes --copy-back or
--move-back transfer files to non-empty directories. Note
that no existing files will be overwritten. If
--copy-back or --nove-back has to copy a file from the
backup directory which already exists in the destination
directory, it will still fail with an error.
即使带上了该参数,如果还存在重名的文件,还是会报错,需要先删除datadir中的重名文件。
5. point-in-time 恢复
利用全备、增量备份最多只能恢复到全备完成时的那一刻,或者增量备份完成时的那一刻的数据。备份之后产生的数据,我们需要结合binlog,来恢复。我们可以从binlog中获得innobackupex最后一次备份完成时的position,它之后的所有的sql,应用完,这些sql,就能将数据库恢复到最新的状态,或者我们想要的某个时间的状态。
1> 先来一个全备:
[[email protected] xtrabackup]# innobackupex /backup/xtrabackup/full --user=bkpuser --password=digdeep
2> 再来一个增量:
将t表数据删除一行:delete from t where i=11;
[[email protected] xtrabackup]# innobackupex --incremental /backup/xtrabackup/incr1/ --incremental-basedir=/backup/xtrabackup/full/2015-11-06_16-26-08 --user=bkpuser --password=digdeep
3> 再来一个增量:
将t表数据删除一行:delete from t where i=10;
[[email protected] xtrabackup]# innobackupex --incremental /backup/xtrabackup/incr2/ --incremental-basedir=/backup/xtrabackup/incr1/2015-11-06_16-31-13/ --user=bkpuser --password=digdeep
4> 备份完成之后,我们再来操作 t 表:
([email protected])[t]mysql>delete from t where i>3;
此时的状态:
([email protected])[t]mysql>show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 927 |
| mysql-bin.000002 | 688 |
+------------------+-----------+
2 rows in set (0.00 sec)
([email protected])[t]mysql>show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000002 | 688 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
假设此时数据库表数据所在的磁盘发生故障,但是 binlog 文件是好的。那么此时,我们就可以使用上面的全备、增量备份、还有binlog文件一起来将数据库恢复到磁盘发生故障那一刻的最新状态来。
5> 首先从全备、增量备份得到最后一次备份完成时的数据:
1)应用全备的redo log:
[[email protected] xtrabackup]# innobackupex --apply-log --redo-only /backup/xtrabackup/full/2015-11-06_16-26-08 --user=bkpuser --password=digdeep
2)应用第一次增量备份的redo log:
[[email protected] xtrabackup]# innobackupex --apply-log --redo-only /backup/xtrabackup/full/2015-11-06_16-26-08 --incremental-dir=/backup/xtr abackup/incr1/2015-11-06_16-31-13/ --user=bkpuser --password=digdeep
3)应用第二次增量备份的 redo log,并且仅限回滚(去掉 --redo-only选项):
[[email protected] xtrabackup]# innobackupex --apply-log /backup/xtrabackup/full/2015-11-06_16-26-08 --incremental-dir=/backup/xtrabackup/incr2/2015-11-06_16-33-57/ --user=bkpuser --password=digdeep
此时已经恢复到了最后一次备份完成时的状态了。
我们看一下最后一次增量备份时的 xtrabackup_binlog_info 文件信息:
[[email protected] xtrabackup]# cat incr2/2015-11-06_16-33-57/xtrabackup_binlog_info
mysql-bin.000002 482
可以看到对应的binlog postion为:mysql-bin.000002 482
而崩溃那一刻的binlog postion为: mysql-bin.000002 688
所以我们需要应用 mysql-bin.000002 文件的 482 到 688之间的sql:
4)先 --copy-back
[[email protected] mysql]# innobackupex --copy-back /backup/xtrabackup/full/2015-11-06_16-26-08 --user=bkpuser --password=digdeep
修改权限:
[[email protected] ~]# chown -R mysql:mysql /var/lib/mysql
启动msyqld: mysqld_safe --user=mysql &
然后验证,t 表的数据,应该有i<10 & i>3 的数据:
([email protected])[t]mysql>select * from t;
+------+
| i |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+------+
9 rows in set (0.00 sec)
如我们所期待的结果一样。说明到此时,前面的操作完全是正确的。
5)应用 mysql-bin.000002 文件的 482 到 688之间的sql
[[email protected] mysql]# mysqlbinlog /backup/xtrabackup/mysql-bin.000002 --start-position=482 > bin.sql
([email protected])[(none)]mysql>source /var/lib/mysql/bin.sql
然后在查看 t 表数据:
([email protected])[t]mysql>select * from t;
+------+
| i |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
一切完美完成,数据库被我们回复到了最新的状态。
6. innobackupex 选项优化/最佳实践
6.1 优化FTWRL锁:
在备份非innodb数据库时,会使用:flush tables with read lock 全局锁锁住整个数据库。如果数据库中有一个长查询在运行,那么FTWRL就不能获得,会被阻塞,进而阻塞所有的DML操作。此时即使我们kill掉FTWRL全局锁也是无法从阻塞中恢复出来的。另外在我们成功的获得了FTWRL全局锁之后,在copy非事务因为的文件的过程中,整个数据库也是被锁住的。所以我们应该让FTWRL的过程尽量的短。(在copy非事务引擎数据的文件时,会阻塞innodb事务引擎。当然也会阻塞所有其他非事务引擎。)
1> 防止阻塞:
innobackupex 提供了多个选项来避免发生阻塞:
--ftwrl-wait-timeout=# 替换 --lock-wait-timeout
This option specifies time in seconds that innobackupex
should wait for queries that would block FTWRL before
running it. If there are still such queries when the
timeout expires, innobackupex terminates with an error.
Default is 0, in which case innobackupex does not wait
for queries to complete and starts FTWRL immediately.
--ftwrl-wait-threshold=# 替换 --lock-wait-threshold
This option specifies the query run time threshold which
is used by innobackupex to detect long-running queries
with a non-zero value of --ftwrl-wait-timeout. FTWRL is
not started until such long-running queries exist. This
option has no effect if --ftwrl-wait-timeout is 0.
Default value is 60 seconds.
--lock-wait-timeout=60 该选项表示:我们在FTWRL时,如果有长查询,那么我们可以最多等待60S的时间,如果60秒之内长查询执行完了,我们就可以成功执行FTWRL了,如果60秒之内没有执行完,那么就直接报错退出,放弃。默认值为0
--lock-wait-threshold=10 该选项表示运行了多久的时间的sql当做长查询;对于长查询最多再等待 --lock-wait-timeout 秒。
--kill-long-queries-timeout=10 该选项表示发出FTWRL之后,再等待多时秒,如果还有长查询,那么就将其kill掉。默认为0,not to kill.
--kill-long-query-type={all|select} 该选项表示我们仅仅kill select语句,还是kill所有其他的类型的长sql语句。
这几个选项,我们没有必要都是有,一般仅仅使用 --lock-wait-timeout=60 就行了。
注意 --lock-* 和 --kill-* 选项的不同,一个是等待多时秒再来执行FTWRL,如果还是不能成功执行就报错退出;一个是已经执行了FTWRL,超时就进行kill。
2> 缩短FTWRL全局锁的时间:
--rsync 使用该选项来缩短备份非事务引擎表的锁定时间,如果需要备份的数据库和表数量很多时,可以加快速度。
--rsync Uses the rsync utility to optimize local file transfers.
When this option is specified, innobackupex uses rsync to
copy all non-InnoDB files instead of spawning a separate
cp for each file, which can be much faster for servers
with a large number of databases or tables. This option
cannot be used together with --stream.
3> 并行优化:
--parallel=# 在备份阶段,压缩/解压阶段,加密/解密阶段,--apply-log,--copy-back 阶段都可以并行
On backup, this option specifies the number of threads
the xtrabackup child process should use to back up files
concurrently. The option accepts an integer argument. It
is passed directly to xtrabackup‘s --parallel option. See
the xtrabackup documentation for details.
4> 内存优化:
--use-memory=# 在crash recovery 阶段,也就是 --apply-log 阶段使用该选项
This option accepts a string argument that specifies the
amount of memory in bytes for xtrabackup to use for crash
recovery while preparing a backup. Multiples are
supported providing the unit (e.g. 1MB, 1GB). It is used
only with the option --apply-log. It is passed directly
to xtrabackup‘s --use-memory option. See the xtrabackup
documentation for details.
3> 备份slave:
--safe-slave-backup
Stop slave SQL thread and wait to start backup until
Slave_open_temp_tables in "SHOW STATUS" is zero. If there
are no open temporary tables, the backup will take place,
otherwise the SQL thread will be started and stopped
until there are no open temporary tables. The backup will
fail if Slave_open_temp_tables does not become zero after
--safe-slave-backup-timeout seconds. The slave SQL thread
will be restarted when the backup finishes.
--safe-slave-backup-timeout=#
How many seconds --safe-slave-backup should wait for
Slave_open_temp_tables to become zero. (default 300)
--slave-info This option is useful when backing up a replication slave
server. It prints the binary log position and name of the
master server. It also writes this information to the
"xtrabackup_slave_info" file as a "CHANGE MASTER"
command. A new slave for this master can be set up by
starting a slave server on this backup and issuing a
"CHANGE MASTER" command with the binary log position
saved in the "xtrabackup_slave_info" file.
1)innobackupex 是perl写的脚本,它调用xtrabackup来备份innodb数据库。而xtrabackup是C语言写的程序,它调用了innodb的函数库和mysql客户端的函数库。innodb函数库提供了向数据文件应用的redo log的功能,而mysql客户端函数库提供了解析命令行参数的功能。innobackupex备份innodb数据库的功能,都是通过调用 xtrabackup --backup和xtrabackup --prepare来完成的。我们没有必要直接使用xtrabackup来备份,通过innobackupex更方便。xtrabakup 通过跳转到datadir目录,然后通过两个线程来完成备份过程:
1> log-copy thread: 备份开始时,该后台线程一直监控redo log(每秒check一次redo log),将redo log的修改复制到备份之后的文件 xtrabackup_logfile 中。如果redo log生成极快时,有可能log-copy线程跟不上redo log的产生速度,那么在redo log文件切换进行覆盖时,xtrabakcup会报错。
2> data-file-copy thread: 前后有一个复制data file的线程,注意这里并不是简单的复制,而是调用了innodb函数库,像innodb数据库那样打开数据文件,进行读取,然后每次复制一个page,然后对page进行验证,如果验证错误,会最多重复十次。
当数据文件复制完成时,xtrabackup 停止log-copy 线程,并建立一个文件 xtrabackup_checkpoints记录备份的类型,开始时的lsn和结束时的lsn等信息。
而备份生成的 xtrabackup_binlog_info 文件则含义备份完成时对应的binlog的position信息,类似于:mysql-bin.000002 120
在备份开始时记录下LSN,然后一个线程复制数据文件,一个线程监控redo log,复制在备份过程中新产生的redo log。虽然我们的到的数据文件显然不是一致性的,但是利用innodb的crash-recovery功能,应用备份过程中产生的redo log文件,就能得到备份完成时那一刻对应的一致性的数据。
注意复制数据文件分成了两个过程:
一个是复制innodb事务引擎的数据文件,是不需要持有锁的;另一个是复制非事务引擎的数据文件和table的定义文件.frm,复制这些文件时,是需要先通过FTWRL,然后在进行复制的,所以会导致整个数据库被阻塞。
增量备份时,是通过对表进行全扫描,比较LSN,如果该page的LSN大于上一次别分时的LSN,那么就将该page复制到table_name.ibd.delta文件中。回复时.delta会和redo log应用到全备是的数据文件中。
增量备份在恢复时,除了最后一次增量备份文件之外,其它的增量备份在应用时,只能前滚,不能执行回滚操作,因为没有提交的事务,可能在下一个增量备份中进行了提交,如果你在上一个增量备份时回滚了,那么下一个增量备份应用时,显然就报错了,因为他无法提交事务,该事务以及被回滚了。
8. 总结:
1)权限:
备份需要两个层面的权限,Linux层面的权限,mysql层面的权限。
2)全备和恢复
全备:innobackupex /backup/xtrabackup/full --user=bkpuser --password=digdeep
应用日志进行prepare: innobackupex --apply-log /backup/xtrabackup/full/2015-11-05_22-38-55/ --user=bkpuser --password=digdeep
关闭mysqld:
copy-back: innobackupex --copy-back /backup/xtrabackup/full/2015-11-05_22-38-55/ --user=bkpuser --password=digdeep
修改权限:chown -R mysql:mysql /var/lib/mysql
3)增量备份和恢复:
全备:
innobackupex --user=bkpuser --password=digdeep /backup/xtrabackup/full
第一次增量备份:
innobackupex --incremental /backup/xtrabackup/incr1/ --incremental-basedir=/backup/xtrabackup/full/2015-11-06_11-29-51/
--user=bkpuser --password=digdeep
第二次增量备份:
innobackupex --incremental /backup/xtrabackup/incr2 --incremental-basedir=/backup/xtrabackup/incr1/2015-11-06_11-33-16/
--user=bkpuser --password=digdeep
恢复:
应用全备redo log:
innobackupex --apply-log --redo-only /backup/xtrabackup/full/2015-11-06_11-29-51/ --user=bkpuser --password=digdeep
应用第一次增量备份的redo log:
innobackupex --apply-log --redo-only /backup/xtrabackup/full/2015-11-06_11-29-51/ --incremental-dir=/backup/xtrabackup/incr1/2015-11-06_11-33-16/
--user=bkpuser --password=digdeep
应用第二次(最后一次)增量备份的redo log:
innobackupex --apply-log /backup/xtrabackup/full/2015-11-06_11-29-51/ --incremental-dir=/backup/xtrabackup/incr2/2015-11-06_11-43-22/
--user=bkpuser --password=digdeep
关闭mysqld,
innobackupex --copy-back /backup/xtrabackup/full/2015-11-06_11-29-51/ --user=bkpuser --password=digdeep
4)部分备份
innobackupex --databases t /backup/xtrabackup/ --user=bkpuser --password=digdeep
innobackupex --apply-log --export /backup/xtrabackup/2015-11-06_15-39-34/ --user=bkpuser --password=digdeep
新建表结构:create table city like t.city;
alter table partial.city discard tablespace;
然后将 city.exp 和 city.ibd 拷贝到 /var/lib/mysql/partial/ 目录下,并修改权限:chown -R mysql:mysql /var/lib/mysql
alter table partial.city import tablespace;
5)point-in-time 恢复
在--copy-back之后,引用binlog文件
mysqlbinlog /backup/xtrabackup/mysql-bin.000002 --start-position=482 > bin.sql
([email protected])[(none)]mysql>source bin.sql
6) innobackupex 选项优化/最佳实践
--ftwrl-wait-timeout=60 防止发生阻塞
--rsync 减少FTWRL时间 缩短备份非事务引擎表的锁定时间
--parallel=4 开并行
--use-memory=4G crash recovery 期间使用的内存
以上是关于xtrabackup8:无全局锁备份原理浅析的主要内容,如果未能解决你的问题,请参考以下文章
基于Xtrabackup8的Mysql定时全量,增量备份及恢复实战演练