本文来自:http://baiyangtx.net/2016/09/04/mydumper-principle/mysql
相对于MySQL官方提供的逻辑备份工具 mysqldump , mydumper最大的特色就是能够采用多线程并行备份,大大提升了数据导出的速度。这里对mydumper的工做原理作个分析,看一下mydumper如何巧妙的利用Innodb引擎提供的MVCC版本控制的功能,实现多线程并发获取一致性数据。sql
这里一致性数据指的是在某个时间点,导出的数据与导出的Binlog文件信息相匹配,若是导出了多张表的数据,这些不一样表之间的数据都是同一个时间点的数据。数据库
在mydumper进行备份的时候,由一个主线程以及多个备份线程完成。其主线程的流程是:多线程
子线程的主要流程是:并发
上述两个线程的流程的关系如图异步
从图中能够看到,主线程释放锁是在子线程开启事物以后。这里是保证子线程得到的数据必定为一致性数据的关键。
主线程在链接到数据库后当即经过Flush tables with read lock(FTWRL) 操做将脏页刷新到磁盘,并获取一个全局的只读锁,这样即可以保证在锁释放以前由主线程看到的数据是一致的。而后当即经过 Start Transaction with consistent snapshot 建立一个快照读事物,并经过 show master status获取binlog位置信息。
而后建立完成dump任务的子线程并为其分配任务。工具
主线程在建立子线程后经过一个异步消息队列 ready 等待子线程准备完毕。 子线程在建立后当即建立到MySQL数据库的链接,而后设置当前事务隔离级别为Repeatable Read。
设置完成以后开始快照读事务。在完成这一系列操做以后,子线程才会经过ready队列告诉主线本身程准备完毕。主线程等待所有子线程准备完毕开启一致性读Snapshot事务后才会释放全局只读锁(Unlock Table)。spa
若是只有Innodb表,那么只有在建立任务阶段会加锁。可是若是存在MyIsam表或其余不带有MVCC功能的表,那么在这些表的导出任务完成以前都必须对这些表进行加锁。Mydumper自己维护了一个 non_innodb_table 列表,在建立任务阶段会首先为非Innodb表建立任务。同时还维护了一个全局的unlock_table队列以及一个原子计数器 non_innodb_table_counter , 子线程每完成一个非Innodb表的任务便将 non_innodb_table_counter 减一,若是non_innodb_table_counter 值为0 遍经过向 unlock_table 队列push一个消息的方式通知主线程完成了非Innodb表的导出任务能够执行 unlock table操做。.net
mydumper支持记录级别的并发导出。在记录级别的导出时,主线程在作任务分配的时候会对表进行拆分,为表的一部分记录建立一个任务。这样作一个好处就是当有某个表特别大的时候能够尽量的利用多线程并发以避免某个线程在导出一个大表而其余线程处于空闲状态。在分割时,首先选取主键(PRIMARY KEY)做为分隔依据,若是没有主键则查找有无惟一索引(UNIQUE KEY)。在以上尝试都失败后,再选取一个区分度比较高的字段作为记录划分的依据(经过 show index 结果集中的cardinality的值肯定)。线程
划分的方式比较暴力,直接经过 select min(filed),max(filed) from table 得到划分字段的取值范围,经过 explain select filed from table 获取字段记录的行数,而后经过一个肯定的步长得到每个子任务的执行时的where条件。这种计算方式只支持数字类型的字段。
以上就是mydumper的并发获取一致性数据的方式,其关键在于利用了Innodb表的MVCC功能,能够经过快照读所以只有在任务建立阶段才须要加锁。