MySQL xtrabackup 物理备份原理
一、简介
xtrabackup 是percona公司开源的MySQL innodb物理备份工具,支持在线热备(备份时不影响数据读写),在工具在业内生产上被大量使用,本次使用xtrabackup 备份的日志和数据库general 日志来对备份的流程和原理进行解读。
二、xtrabackup备份原理:
1、xtrabackup 之所以可以通过复制 InnoDB 表的 ibd 文件工作,是由于 InnoDB 内部维护了一个重做日志(redo log)。redo log包含了每次 InnoDB 会更改数据的记录。当 Innodb 启动时,它会检查数据文件并重做日志,并执行以下两步操作:应用已经提交的事务(前滚),回滚那些未提交的事务(回滚)
2、Xtrabackup在启动时会记住log sequence number(LSN),并且复制所有的数据文件。同时xtrabackup会运行一个后台进程,用于监视事务日志,并从事务日志复制最新的修改。所以xtrabackup自启动开始,就不停的将事务日志中每个数据文件的修改都记录下来。
3、innobackupex不支持在线备份MyISAM表,当xtrabackup复制完innodb数据文件后,会执行FLUSH TABLES WITH READ LOCK来阻止新的写入进来并把MyISAM表数据刷到硬盘上,之后复制MyISAM数据文件,最后释放锁。
4、准备(prepare)过程,xtrabackup使用之前复制的事务日志,对各个数据文件执行灾难恢复(就像mysql刚启动时要做的一样),将表数据前滚到FLUSH TABLES WITH READ LOCK的时间点;所以myisam表数据与InnoDB表数据是同步的。类似oracle的,InnoDB的prepare过程可以称为recover(恢复),myisam的数据复制过程可以称为restore(还原)。
注:InnoDB 和非 InnoDB 文件的备份都是通过拷贝文件来做的,但是实现的方式不同,前者是以page为粒度做的(xtrabackup),后者是 cp 或者 tar 命令(innobackupex),xtrabackup 在读取每个page时会校验 checksum 值,保证数据块是一致的,而 innobackupex 在 cp MyISAM 文件时已经做了flush(FTWRL),磁盘上的文件也是完整的,所以最终备份集里的数据文件都是写入完整的。
三、xtrabackup备份流程
![](http://media.teamshub.com/10000/tm/2019/11/05/b95bd350-c659-4344-a14c-357b5a01bcd6/425f6072-9503-4c4a-9c26-bfad320f8d74.png)
1、innobackupex 在启动后,会先 fork 一个进程,启动 xtrabackup进程,记录当前的LSN号,然后就等待 xtrabackup 备份完 ibd 数据文件;
2、xtrabackup 在备份 InnoDB 相关数据时,是有2种线程的,1种是 redo 拷贝线程,负责拷贝 redo 文件,1种是 ibd 拷贝线程,负责拷贝 ibd 文件;redo 拷贝线程只有一个,在 ibd 拷贝线程之前启动,在 ibd 线程结束后结束。xtrabackup 进程开始执行后,先启动 redo 拷贝线程,从最新的 checkpoint 点开始顺序拷贝 redo 日志;然后再启动 ibd 数据拷贝线程,在 xtrabackup 拷贝 ibd 过程中,innobackupex 进程一直处于等待状态(等待文件被创建)。
3、xtrabackup 拷贝完成idb后,通知 innobackupex(通过创建文件),同时自己进入等待(redo 线程仍然继续拷贝);
4、innobackupex 收到 xtrabackup 通知后,执行FLUSH TABLES WITH READ LOCK (FTWRL),取得一致性位点,然后开始备份非 InnoDB 文件(包括 frm、MYD、MYI、CSV、opt、par等)。拷贝非 InnoDB 文件过程中,因为数据库处于全局只读状态,如果在业务的主库备份的话,要特别小心,非 InnoDB 表(主要是MyISAM)比较多的话整库只读时间就会比较长,这个影响一定要评估到。
5、当 innobackupex 拷贝完所有非 InnoDB 表文件后,通知 xtrabackup(通过删文件) ,同时自己进入等待(等待另一个文件被创建);
6、xtrabackup 收到 innobackupex 备份完非 InnoDB 通知后,就停止 redo 拷贝线程,然后通知 innobackupexredo log 拷贝完成(通过创建文件);
7、innobackupex 收到 redo 备份完成通知后,就开始解锁,执行 UNLOCK TABLES;
8、最后 innobackupex 和 xtrabackup 进程各自完成收尾工作,如资源的释放、写备份元数据信息等,innobackupex 等待 xtrabackup 子进程结束后退出。
四、xtrabackup常用命令选项:
完整的选项使用请执行innobackupex –help,这里只介绍使用常用的选项进行完整备份及增量备份和还原,这里只对常用参数进行描述
-u, --user=name:备份时连接数据的用户名称。
-H, --host=name:指定数据库的 IP 地址或者主机名(如果主机名可以解析的话)
-P, --port=#:连接数据库的端口号。
-p, --password=name:连接数据库用户的密码。
-S, --socket=name:该选项接受一个字符串参数,可以指定使用 UNIX 套接字的方式连接到本地数据库。
–defaults-file 数据库的配置文件路径,感觉本地备份不写也可以,远程没测试过。
–no-timestamp 创建备份时不自动生成时间目录,可以自定义备份目录名例如: /backups/mysql/base
–databases 用于指定要备份的数据库, 多个库文件使用方法: “database1 database2″,对innodb表无用
–incremental 在全备份的基础上进行增量备份,后跟增量备份存贮目录路径
–incremental-basedir=DIRECTORY 增量备份所需要的全备份路径目录或上次做增量备份的目录路径
–incremental-dir=DIRECTORY 增量备份存贮的目录路径
–redo-only 用于准备增量备份内容把数据合并到全备份目录,配合–incremental-dir 增量备份目录使用。
–force-non-empty-directories 如果是特定库备份还原,不需要删掉整个mysql目录,只是特定库的及相关文件就可以,还原时加上此参数就不会报错。
--apply-log:通过应用 BACKUP_DIR 目录中的 xtrabackup_logfile 的事务日志,在 BACKUP_DIR 目录中准备备份,并且创建新的事务日志。innobackupex --apply-log 默认使用 BACKUP_DIR 目录 backup-my.cnf 中的 InnoDB 配置,如果指定了--defaults-file 选项,那么就使用它指定的配置文件。
--copy-back:将准备好的备份文件从备份目录复制到原始位置,其原始位置目录必须为空,否则报错(除非指定--force-non-empty-directories 选项)。
--move-back:将之前备份的所有文件从备份目录移动到原始目录。此选项恢复后将删除备份文件,请大家慎重使用。
--stream=name:该选项接受指定流备份执行格式的字符串参数,备份将以指定的格式完成 STDOUT。对备份文件进行打包。支持格式有 tar 和 xbstream。如果在该选项后指定路径,则该路径被解释为 tmpdir 的值。
--tables-file=name:
-t, --tmpdir=name:该选项接受一个指定临时文件位置的字符串参数。它可以与--stream 选项一起使用。使用该选项,事务日志首先会存储到临时文件中,然后流式传输或者复制到远程主机。如果未指定该选项,则默认值为使用 my.cnf 配置读取的 tmpdir 值。
--use-memory=#:该选项指定 xtrabackup 在 prepare 阶段进行崩溃恢复的内存使用量,以字节为单位,支持的单位如 1MB、1M、1GB、1G。
--slave-info:该选项用于在从库上的备份。它会打印二进制日志的位置和主库的名称,还会将此信息以“CHANGE MASTER”命令的形式写入到 xtrabackup_slave_info 文件中,可以通过此备份启动从实例。
--safe-slave-backup:这个选项是要和--slave-info 结合使用的。发起备份时,会暂停 SLAVE 的 SQL Thread,确保备份时没有临时表打开,保证数据的一致性。备份结束后,SQL 线程会自动启动。如果 Slave_open_temp_tables 在--safe-slave-backup-timeout 秒后未变成零,则备份失败。
--safe-slave-backup-timeout=seconds:该选项指定--safe-slave-backup 应等待多长时间,以使 Slave_open_temp_tables 变为零。默认时间为 300 秒
--lock-ddl
备份开始时候阻塞所有DDL操作
--lock-ddl-per-table
在xtrabackup开始复制每个表之前和备份完成之前,都要阻塞对该表的DDL操作。
--lock-ddl-timeout
在指定的时间内没有返回,就终止备份
--parallel
整数参数,指定xtrabackup子进程用于同时备份文件的线程数。 请注意,此选项适用于文件级别,即,如果您有多个.ibd文件,则它们将并行复制。 如果表一起存储在单个表空间文件中,则它将无效。此选项将允许同时解密和/或解压缩多个文件
--no-version-check
不检查版本
五、xtrabackup备份实践
备份:
普通全备:
innobackupex --defaults-file=/dbdata/3306/3306.cfg --user=root --password=xxxx --socket=/dbdata/3306/mysql.sock --no-timestamp --lock-ddl-per-table --no-version-check --parallel=4 --slave-info /dbdata/testbak2 >/dbdata/backup.log 2>&1
使用tar压缩全备:
innobackupex --defaults-file=/dbdata/3306/3306.cfg --user=root --password=xxxx --socket=/dbdata/3306/mysql.sock --no-timestamp --lock-ddl-per-table --no-version-check --parallel=4 --slave-info --stream=tar
tmpdir=/dbdata |gzip >/dbdata/backup.tar.gz
增量备份:
innobackupex --defaults-file=${mycnf} --user=${user} --password=${password} --use-memory=1G --no-timestamp --incremental ${backuppath}/${incrbakdir} --incremental-basedir ${backuppath}/${backupdir}
全备恢复:
全备恢复:
innobackupex --defaults-file=/dbdata/mysql5718/mysql3306/my.cnf --use-memory=8G --apply-log
/dbdata/2017-05-11_21-53-56
innobackupex --defaults-file=/dbdata/mysql5718/mysql3306/my.cnf --use-memory=8G --copy-back /dbdata/2017-05-11_21-53-56
增量备份恢复:
1)先应用完整备份
innobackupex --defaults-file=/dbdata/mysql5718/mysql3306/my.cnf --use-memory=8G --apply-log --redo-only /dbdata/2017-05-11_21-53-56
2)应用增量备份
innobackupex --defaults-file=/dbdata/mysql5718/mysql3306/my.cnf --use-memory=8G --apply-log --redo-only --incremental-dir=/xxx/inr_xx /dbdata/2017-05-11_21-53-56
(如果有多个增备,仅仅最后一个增备无需指定--redo-only )
远程备份:
非压缩方式
innobackupex --stream=tar /tmp | ssh root@192.168.1.7 / "cat - > /backup/bak.tar"
压缩方式
innobackupex --stream=tar /tmp | ssh root@192.168.1.7 / "gzip >/backup/bak.tar.gz"
六、xtrabackup备份日志分析
180802 15:10:15 Connecting to MySQL server host: localhost, user: root, password: set, port: 3306, socket: /dbdata/3306/mysql.sock
Using server version 5.7.21-log
./innobackupex version 2.4.7 based on MySQL server 5.7.13 Linux (x86_64) (revision id: 05f1fcf)
xtrabackup: uses posix_fadvise().
xtrabackup: cd to /dbdata/3306/data
xtrabackup: open files limit requested 65535, set to 65535
xtrabackup: using the following InnoDB configuration:
xtrabackup: innodb_data_home_dir = .
xtrabackup: innodb_data_file_path = ibdata1:512M:autoextend
xtrabackup: innodb_log_group_home_dir = ./
xtrabackup: innodb_log_files_in_group = 3
xtrabackup: innodb_log_file_size = 268435456
2018-08-02 15:10:15 0x7f78c6d8c740 InnoDB: Using Linux native AIO
xtrabackup: using O_DIRECT
InnoDB: Number of pools: 1
180802 15:10:15 >> log scanned up to (1873374524)
redo拷贝线程开始拷贝redo中新增的
xtrabackup: Generating a list of tablespaces
InnoDB: Allocated tablespace ID 2 for mysql/plugin, old maximum was 0
xtrabackup: Starting 4 threads for parallel data files transfer
180802 15:10:15 [01] Copying ./ibdata1 to /dbdata/testbak2/ibdata1
拷贝innodb引擎的数据文件
180802 15:10:15 [02] Copying ./mysql/plugin.ibd to /dbdata/testbak2/mysql/plugin.ibd
.....................................
180802 15:10:16 [02] Copying ./test01/qrtz_job_details.ibd to /dbdata/testbak2/test01/qrtz_job_details.ibd
180802 15:10:16 [03] Copying ./sys/sys_config.ibd to /dbdata/testbak2/sys/sys_config.ibd
180802 15:10:16 [04] Copying ./test01/qrtz_triggers.ibd to /dbdata/testbak2/test01/qrtz_triggers.ibd
......................................
180802 15:10:18 >> log scanned up to (1873374524)
180802 15:10:18 Executing FLUSH NO_WRITE_TO_BINLOG TABLES...
关闭所有表(操作不发送到slave)
180802 15:10:18 Executing FLUSH TABLES WITH READ LOCK...
全局读锁
180802 15:10:18 Starting to backup non-InnoDB tables and files
开始拷贝非innodb表和文件
180802 15:10:18 [01] Copying ./mysql/db.opt to /dbdata/testbak2/mysql/db.opt
180802 15:10:18 [01] ...done
.................................................
180802 15:10:19 [01] Copying ./test01/qrtz_job_details.frm to /dbdata/testbak2/test01/qrtz_job_details.frm
180802 15:10:19 [01] ...done
.................................................
180802 15:10:19 Finished backing up non-InnoDB tables and files
180802 15:10:19 [00] Writing xtrabackup_slave_info
写入show slave status信息
180802 15:10:19 [00] ...done
180802 15:10:19 [00] Writing xtrabackup_binlog_info
写入show master status信息
180802 15:10:19 [00] ...done
180802 15:10:19 Executing FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS...
刷新 redo log buffer 中的日志到磁盘中
xtrabackup: The latest check point (for incremental): '1873374515'
xtrabackup: Stopping log copying thread.
180802 15:10:19 >> log scanned up to (1873374524)
最后一次拷贝redo
180802 15:10:19 Executing UNLOCK TABLES
解锁表
180802 15:10:19 All tables unlocked
180802 15:10:19 [00] Copying ib_buffer_pool to /dbdata/testbak2/ib_buffer_pool
180802 15:10:19 [00] ...done
180802 15:10:19 Backup created in directory '/dbdata/testbak2/'
MySQL binlog position: filename 'bin-log.000018', position '96573286', GTID of the last change '237931e4-52a1-11e8-9d07-000c293ddb5b:5-9,
ab805be6-52a0-11e8-9e8c-000c2925c742:1-1544667'
MySQL slave binlog position: master host '192.168.73.102', purge list '237931e4-52a1-11e8-9d07-000c293ddb5b:5-9, ab805be6-52a0-11e8-9e8c-000c2925c742:1-1544667'
180802 15:10:19 [00] Writing backup-my.cnf
180802 15:10:19 [00] ...done
180802 15:10:19 [00] Writing xtrabackup_info
180802 15:10:19 [00] ...done
xtrabackup: Transaction log of lsn (1873374515) to (1873374524) was copied.
180802 15:10:19 completed OK!
备份完成
七、xtrabackup备份的general_log分析
Id Command Argument
11998 Connect root@localhost on using Socket
11998 Query SET SESSION wait_timeout=2147483
调整session级别wait_timeout值
11998 Query SHOW VARIABLES
11998 Query SHOW ENGINE INNODB STATUS
11998 Query SET SESSION lock_wait_timeout=31536000
调整session级别lock_wait_timeout值
11998 Query FLUSH NO_WRITE_TO_BINLOG TABLES
关闭打开的表
11998 Query FLUSH TABLES WITH READ LOCK
FTWRL全局读锁
11998 Query SHOW SLAVE STATUS
获取复制信息
11998 Query SHOW VARIABLES
11998 Query SHOW MASTER STATUS
获取本机的binlog信息
11998 Query SHOW VARIABLES
11998 Query FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS
刷新buffer中的redo到redo log file中
11998 Query UNLOCK TABLES
解锁
11998 Query SELECT UUID()
11998 Query SELECT VERSION()
11998 Quit
退出
与mysqldump的general_log相比,最主要是多了
FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS这一步骤,因为5.6后group commit中的innodb commit不需要在做sync操作,如果不执行flush engine logs ,因为xtrabackup不备份Binlog,恢复时则可能会丢失部分数据。
引用: