看一下几个版本以来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上执行事务的顺序不变。