看一下几个版本以来binlog复制策略的演进。

 

5.6以前的版本

经典的主从复制模型:

1,Master提交事务。

2,binlog写入binlog文件。

3,Slave的IO线程把Master上的binlog写入Slave的RelayLog。

4,Slave单线程从RelayLog中读取日志并执行。

瓶颈:单线程处理RelayLog太慢。

 

5.6版本

开始使用库级的并行复制,为了优化单线程处理RelayLog太慢的问题。

有SQL线程作为Coordinator调度线程,同时启动多个线程作为WorkThread工作线程,调度线程读取RelayLog文件内容,判断是否跨库,然后分配给不同的工作线程来处理。

单库模式下,效率可能还没有原来的模式快。

 

5.7版本

开始使用基于Group Commit的并行复制。

 

Group Commit解决的问题:

Master提交事务时,需要将binlog写入磁盘文件并调用fsync磁盘同步指令,这是一个加锁的操作,所以写入binlog还是串行的。提交事务并发比较高时,效率比较慢。

 

Group Commit的策略:

把提交事务的过程分为三个阶段,分别是Flush,Sync,Commit,每个阶段维护一个队列,由队列中的第一个线程执行该阶段的操作。达到的效果是可以一次把一批事务的binlog写到磁盘文件。每次一起提交的文件属于一个Group。

根据InnoDB事务的原理,Group Commit中的事务应该是没有行级锁的冲突,一批事务在Slave中可以并行处理。

 

在binlog中会记录两个值,last_committed 和 sequence_number。

sequence_number:事务编号,全局唯一。

last_committed:上组事务中最后提交的那个事务的编号。

那么,两个事务如果last_committed相同,代表他们是同一组提交的事务。

 

相关参数:

slave_parallel_type:回放策略。设为DATABASE表示采用5.6版本的库级并行复制,设为LOGICAL_LOCK表示采用5.7版本的Group Commit策略。

binlog_group_commit_sync_delay:为Group Commit而设定的commit延迟。

binlog_group_commit_sync_no_delay_count:为Group Commit而设定的不再等待延迟的事务数。

以上两个参数是为了Master并发不大时也能享受到Group Commit的性能提高。

 

8.0版本

使用WriteSet策略。

在Master生成binlog时,不再按照Group提交,而是通过WriteSet策略,使用写集合,判断提交的事务是否有依赖关系。

 

更详细一点的WriteSet策略流程:

1,建立vector变量保存已提交事务的Hash值。

2,如果某事务修改的行里面有主键,则vector保存主键(及库,表等信息)的Hash值,有非空唯一键,则保存非空唯一键(及库,表等信息)的Hash值,如果有外键,则保存外键的Hash值,以上都没有,vector不保存该事务信息。

3,如果某事务修改的行的主键是其他表的外键,则此事务不参与此策略,vector不保存此事务的信息。

4,如果某事务最终没有被vector保存信息,则此事务不参与此策略。

5,比较事务的vector信息,无冲突则表示可以一起提交,last_committed改为最后一个已提交的事务相同的last_committed。

6,一起提交的事务最终被并行处理。不参与此策略的事务使用5.7版本的组提交策略。

 

注:

1,WriteSet策略依赖主键或者非空唯一键。

2,WriteSet策略需要把Binlog设为Row格式。

3,此策略在Master生成binlog时就生效,所以即使Slave不是8.0版本也能享受此策略的优化。

 

相关系统变量

binlog-transaction-dependency-tracking

此系统变量可设置以下三个值:

COMMIT_ORDER:5.7版本的组提交策略。

WRITESET:基于WriteSet的策略。效率最高。

WRITESET_SESSION:基于WriteSet的策略后再次计算,可以保证同一个session在Slave上执行事务的顺序不变。