我们知道从5.6开始,MySQL支持多线程复制,到5.7版本又引入了基于GROUP COMMIT的并发事务分发机制。这意味着没有冲突的事务可以在备库并发执行。很显然,备库的事务提交顺序和主库是不能保证一致的。
这可能带来一些问题,尤其是事务之间有一定的业务关联时,提供读访问时可能会带来业务上的不一致问题。因此在MySQL 5.7.6版本,引入了一个新的特性,来保证主库和备库的commit顺序是一致的。
对应的changelog:
Replication: Multi-threaded slaves can use the new slave_preserve_commit_order variable to ensure that the order which transactions were committed on the master is preserved on the slave. This prevents the slave from entering a state that the master was not in and is well suited to using multi-threaded slaves for replication read scale-out.
worklog:http://dev.mysql.com/worklog/task/?id=6813
代码:http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/7985
主要修改思路:
增加了新类Commit_order_manager,来维护COMMIT的worker队列顺序。当START SLAVE时,发现选项被打开,使用多线程复制,并且备库的log_slave_update和binlog均打开时,就初始化一个类对象(handle_slave_sql)
当使用基于LOGIC CLOCK的方式来分发事务时,这些被分发的事务拥有相同的标记(在主库上同时被提交,可以确保没有事务冲突),因此可以被备库的worker线程并发执行。
在分配事务给一个worker线程时,worker入队列(Mts_submode_logical_clock::get_least_occupied_worker),调用函数Commit_order_manager::register_trx, 线程状态设置为OCS_WAIT
在事务commit,进入GROUP COMMIT的FLUSH STAGE之前,如果当前worker之前还有事务没有进入FLUSH STAGE,则等待(Commit_order_manager::wait_for_its_turn);直到该worker成为队列头,状态设置为OCS_SIGNAL。
进入FLUSH STAGE后,当前Worker会通知它的后一个worker可以进入FLUSH STAGE了,并将自己从队列中移除(mngr->unregister_trx(worker))。worker状态修改为OCS_FINISH。
由于FLUSH STAGE主要用于将binlog 从cache刷入文件,因此只要在该阶段保证有序即可。
另外为了保证有序性,一旦前面的事务执行失败,排在后面的worker都需要进行回滚。