1. 单线程复制
单线程复制是MySQL最早出现的主从复制技术,本节我们将对单线程复制做进一步说明。
在MySQL5.6之前的版本中,从库复制不支持多线程,所以当主库写压力稍微大一点时,从库就会出现复制延迟。当然,目前的最新版本已经能够很好地支持并行复制了。为了便于理解复制的演进历程,这里简单地对单线程复制做一个小小的剖析。下面以在单线程复制中主库写入binlog中的日志解析记录为例,对单线程复制原理进行细化阐述。假设某个事务的INSERT操作在binlog中的记录如下:
从库的SQL线程从relay log中读取并解析主库的binlog变更日志,然后所有的事件依次串行执行。而binlog的写入时机是在事务完成对数据修改且事务发起Commit(提交)之后,也就是说,主库事务先执行,然后产生的binlog发送到从库执行。
从理论上讲,一前一后的时差必然会导致从库复制延迟,如果碰到大事务,则会急剧放大从库延迟(例如:主库执行一个大事务耗费1小时完成,从库收到这个事务之后开始执行时,就已经落后于主库1小时了)。也正是因为串行复制的诸多弊端,推动着串行复制向着并行复制发展。
提示:前面说到,在MySQL 5.6之前的版本中从库不支持并行复制,但实际上启用了binlog之后主库本身也不支持并行事务提交。当不启用binlog时,InnoDB存储引擎本身是支持Group Commit(即一次提交多个事务)的,但是当启用binlog之后,为了保证数据的一致性(也就是必须要保证MySQL服务器层和存储引擎层的提交顺序一致),启用了两阶段提交。
而两阶段提交中的Prepare(提交准备)阶段使用了prepare_commit_mutex互斥锁来强制事务串行提交,这也大大降低了数据库的写入效率。
2. DATABASE并行复制
顾名思义,DATABASE并行复制就是在串行复制的基础上进行的改进,是基于库级别的并行复制。从MySQL 5.6 开始,支持基于库级别的并行复制(这也是最早出现的并行复制机制),在binlog中记录的内容类似如下:
从以上对INSERT语句的binlog解析内容来看,与MySQL 5.5 版本比较几乎没有什么变化,那么从MySQL 5.6版本开始,对复制的改进点主要是什么呢?
对于实例自身而言(不区分主从库),在原先的两阶段提交中移除了prepare_commit_mutex互斥锁,为保证binlog的提交顺序和存储引擎层的提交顺序一致,引入了类似于InnoDB存储引擎层的Group Commit机制,称为Binary Log Group Commit(BLGC)。
在MySQL服务器层进行提交时,首先按照顺序将其放入一个队列中,队列中的第一个事务称为Leader(领队者),其他事务称为Follower(跟随者),Leader控制着Follower的行为。
一旦前一个阶段中的队列任务执行完成,后一个阶段队列中的Leader就会带领它的Follower进入前一个阶段的队列中执行,这样就使得并行提交可以源源不断地进行下去。
BLGC的步骤分为如图18-11所示的三个阶段(该图来自http://mysqlmusings.blogspot.com/)。
- Flush(刷新)阶段,将每个事务的binlog写入内存中。
- Sync(同步)阶段,将内存中的binlog同步到磁盘。
若队列中有多个事务,那么仅一次fsync操作就完成了多个事务的binlog写入,这就是BLGC。 - Commit(提交)阶段,Leader根据顺序调用存储引擎层事务的提交。
InnoDB存储引擎本就支持Group Commit,因此修复了原先由prepare_commit_mutex互斥锁导致InnoDB 存储引擎层Group Commit失效的问题。这样一来,在启用binlog的情况下,数据库中的事务并行提交就得以实现了。
对于从库而言,主要的改进点是在从库复制的SQL线程上增加了一个SQL协调器(Coordinator)线程,真正干活的SQL线程被称之为Worker(工作)线程,当Worker线程数量为N(N>1)以及主库的schema数量为N时,从库就可以根据基于多个schema之间相互独立(彼此之间无锁冲突)的语句来实现并行复制;
反之,如果N=1,则仍然跟MySQL 5.6之前版本中的单线程复制没有太大区别。
主库无须设置任何参数,只需要在从库上修改设置Worker线程数量的参数即可,如下所示。