多线程复制
将sql_thread拆分为coordinator和多个worker
- coordinator只负责读取中转日志和分发事务
- worker线程负责更新日志,worker个数由slave
_parallel_workers设定,这个值设置为8~16之间最好(32核物理机的情况)
多线程,为了保证一致性,分发事务需要满足以下基本要求:
- 不能造成更新覆盖。这就要求更新同一行的两个事务,必须被分发到同一个worker中。
- 同一个事务不能被拆开,必须放到同一个worker中。
前提条件
- 要能够从binlog里面解析出表名、主键值和唯一索引的值。也就是说,主库的binlog格式必须是row;
- 表必须有主键;
- 不能有外键。表上如果有外键,级联更新的行不会记录在binlog中,这样冲突检测就不准确。
按表分发策略
如果两个事务更新不同的表,它们就可以并行。因为数据是存储在表里的,所以按表分发,可以保证两个worker不会更新同一行。
设计思路
每个worker线程维护一个hash表,用于保存当前正在这个worker的“执行队列”里的事务所涉及的表。hash表的key是“库名.表名”,value是一个数字,表示队列中有多少个事务修改这个表。
事务分发时:
- 如果都不冲突,则分配给最空闲的worker
- 如果有多个冲突,需要等待
- 只有一个冲突时,分配给冲突的worker
在多个表负载均衡时很有效,但是对于热点表会基本变成单线程复制
按行分发策略
按行复制的核心思路是:如果两个事务没有更新相同的行,它们在备库上可以并行执行。这个模式要求binlog格式必须是row。
- 此时判断一个事务T和worker是否冲突,用的就规则就不是“修改同一个表”,而是“修改同一行”
- 按行复制也是为每个worker,分配一个hash表。只是要实现按行分发,这时候的key,就必须是“库名+表名+唯一键的值”。有时候除了主键,还需要考虑唯一索引
- 此种方案分发时需要更多资源;1.耗费内存。比如一个语句要删除100万行数据,这时候hash表就要记录100万个项 2.耗费CPU。解析binlog,然后计算hash值,对于大事务,成本还是很高。
按库分发策略
也是为每个worker,分配一个hash表。实现按库分发,这时候的key就是数据库名。
- 如果主库多个db负载均衡,则效果很好
- 优势在于:1.构建hash值很快,只需要库名,同时由于库数量不多,key项也不会很多。2.不要求binlog的格式。因为statement格式的binlog也可以很容易拿到库名
模拟主库并行模式策略
利用了redo log组提交的特性(MariaDB的策略)
- 能够在同一组里提交的事务,一定不会修改同一行;
- 主库上可以并行执行的事务,备库上也一定是可以并行执行的
实现思路
- 在一组里面一起提交的事务,有一个相同的commit id,下一组就是commit id+1;
- commit id直接写到binlog里面
- 传到备库应用的时候,相同commit id的事务分发到多个worker执行;
- 这一组全部执行完成后,coordinator再去取下一批
注意
1.事务在备库上执行的时候,不能完全与主库一样并行,要等第一组事务完全执行完成后,第二组事务才能开始执行,系统的吞吐量不够
2.大事务影响较大,会变成单线程
Mysql 5.7
slave_parallel_type来控制并行复制策略:
1.配置为DATABASE,表示使用MySQL 5.6版本的按库并行策略
2. 配置为LOGICAL_CLOCK,表示的就是类似MariaDB的策略并针对并行度做了优化:处于所有执行中的状态不能并行,所有处于redo log prepare状态的事务可以并行(此时已经通过了锁冲突检测)
- 同时处于prepare状态的事务,在备库执行时是可以并行;
- 处于prepare状态的事务,与处于commit状态的事务之间,在备库执行时也是可以并行
基于WRITESET的并行复制
MySQL5.7.22 增加了一个新的并行复制策略,基于WRITESET的并行复制。
新增了一个参数binlog-transaction-dependencytracking,用来控制是否启用这个新策略。这个参数的可选值有以下三种。
- COMMIT_ORDER,表示的就是前面介绍的,根据同时进入prepare和commit来判断是否可以并行的策略。
- WRITESET,表示的是对于事务涉及更新的每一行,计算出这一行的hash值,组成集合witeset。如果两个事务没有操作相同的行,也就是说它们的writeset没有交集,就可以并行。
- WRITESET_SESSION,是在WRITESET的基础上多了一个约束,即在主库上同一个线程先后执行的两个事务,在备库执行的时候,要保证相同的先后顺序。
后面两种相当于按行分发策略,但是优势在于:
- writeset是在主库生成后直接写入到binlog里面的,这样在备库执行的时候,不需要解析binlog内容
(event里的行数据),节省了很多计算量; 不需要把整个事务的binlog都扫一遍才能决定分发到哪个worker,更省内存;
由于备库的分发策略不依赖于binlog内容,所以binlog是statement格式也是可以的。因此,MySQL
5.7.22的并行复制策略在通用性上还是有保证的
当然,对于“表上没主键”和“外键约束”的场景,WRITESET策略也是没法并行的,也会暂时退化为单线程模型。