Xtrabackup备份原理实现细节——对淘宝数据库内核月报的补充
前言
淘宝3月的数据库内核月报对xtrabackup的备份原理做了深入的分析,写的还是很不错。不过Inside君在看完之后,感觉没有对一个细节问题进行比较深入的介绍,而此问题可能会导致备份文件恢复后丢失相关数据。之前Inside君在MySQL 5.6对于Xtrabackup的影响一文中已经做了简单的说明,今天借着淘宝数据库内核组的文章再拿来提醒下各位小伙伴。
Inside君还是先给出结论:尽可能地使用新版本Xtrabackup工具备份MySQL数据库。
PS:最后1个月,赶快报名2016年MySQL技术嘉年华吧(请点击)
正文
在淘宝数据库内核组的文章中写到Xtrabackup在备份结束时会按下面的步骤执行操作(有所简化,具体见原文):
FLUSH TABLES WITH READ LOCK(FTWRL)
拷贝所有非事务表,如系统MyISAM表
拷贝重做日志
UNLOCK TABLES
但是这里少了一个步骤,那就是在拷贝重做日志前,备份工具还会去执行如下操作,该操作会将InnoDB层的重做日志持久化到磁盘然后再进行拷贝:
FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS
这个细节非常关键,因为不执行该操作可能会导致备份丢失一部分的数据。若再进行主从复制的话,同步可能报错。如果要分析原因,还是得从下面的提交过程图来看:
在上图显示的事务提交过程中,骤会1进行一次fsync,确保日志落盘。但是从MySQL 5.6版本开始,已经不再需要步骤2执行fsync,即减少I/O操作提升数据库的性能,而这对数据一致性是没有影响的,因为已经写入到二进制日志的事务在恢复的过程中一定是提交的。然而,问题在于Xtrabackup备份并不拷贝二进制日志。那么就有可能在恢复过程中存在下面的这种情况:
也就是说如果Xtrabackup备份的时候没有备份上图左边的最后一个InnoDB的commit log,这个事务在恢复的过程中就会丢失,简单来说就是数据丢失。Xtrabackup 2.2.3版本修复了此问题,具体可见:https://launchpad.net/percona-xtrabackup/2.2/2.2.3-ga
另外一个小细节是Xtrabackup备份是,如果数据库是Percona Server分支版本的话,那么其使用的不是FLUSH TABLE WITH READ LOCK来获取位置信息,这样的需要把表都关了,而且InnoDB表这时也将不可写入。因此Percona Server版本新增了两个新的命令LOCK TABLES FOR BACKUP和LOCK BINARY LOG FOR BACKUP,因此备份流程变为了:
LOCK TABLES FOR BACKUP
... copy .frm, MyISAM, CSV, etc. ...
LOCK BINLOG FOR BACKUP
UNLOCK TABLES
... get binlog coordinates ...
... wait for redo log copying to finish ...
UNLOCK BINLOG
按照上述逻辑实现的话,InnoDB表只会在备份的最后获取二进制日志位置时被锁住,相对原来的实现锁定的时间又有进一步的缩短。当然这取决于你非事务表的数量,如果全是InnoDB存储引擎用户表的话,那么提升也是有限的。
研究备份实现原理还是非常有意思的一件事情,比如Xtrabackup增量备份的实现其实还存在另一些细节可挖掘。若有小伙伴想进一步掌握内部的实现原理,可以去GitHub上翻看下Xtrabackup的源码哦~~~
历史阅读
MySQL 5.7中新增的表gtid_executed,看看是否解决了你的痛点
有态度的公众账号