备库并行复制
在主库上,影响并发度的原因就是各种锁了,除了极端场景外,他对业务并发度的支持还是很友好的。但在备库上,sql_thread更新数据的时候,如果是用单线程的话,就会导致备库应用日志不够快,造成主备延迟。在官方5.6版本之前,主库高并发,高TPS就会出现严重的主备延迟问题。
多线程复制机制
类似nginx的master-worker,coordinator(sql_thread)不再更新数据,负责读取中转日志和分发事务,有worker线程更新日志,个数由参数slave_parallel_workers决定。这个值设置为8~16之间最好(32核CPU)。
coordinator 在分发的时候,需要满足以下这两个基本要求:不能造成更新覆盖。这就要求更新同一行的两个事务,必须被分发到同一个 worker 中。同一个事务不能被拆开,必须放到同一个 worker 中。
MySQL 5.5 版本的并行复制策略
官方 MySQL 5.5 版本是不支持并行复制的
按表分发策略
如果跟所有 worker 都不冲突,coordinator 线程就会把这个事务分配给最空闲的 woker;
如果跟多于一个 worker 冲突,coordinator 线程就进入等待状态,直到和这个事务存在冲突关系的 worker 只剩下 1 个;
如果只跟一个 worker 冲突,coordinator 线程就会把这个事务分配给这个存在冲突关系的 worker。
按行分发策略
相比于按表并行分发策略,按行并行策略在决定线程分发的时候,需要消耗更多的计算资源。
约束条件
要能够从 binlog 里面解析出表名、主键值和唯一索引的值。也就是说,主库的 binlog 格式必须是 row;
表必须有主键;
不能有外键。表上如果有外键,级联更新的行不会记录在 binlog 中,这样冲突检测就不准确。
以上两个策略没有被合到官方。
MySQL 5.6 版本的并行复制策略
官方 MySQL5.6 版本,支持了并行复制,只是支持的粒度是按库并行。如果在主库上有多个 DB,并且各个 DB 的压力均衡,使用这个策略的效果会很好。用的不多。
MariaDB 的并行复制策略
MariaDB 的并行复制策略利用的了组提交的特性:能够在同一组里提交的事务,一定不会修改同一行;主库上可以并行执行的事务,备库上也一定是可以并行执行的。
具体实现:在一组里面一起提交的事务,有一个相同的 commit_id,下一组就是 commit_id+1;commit_id 直接写到 binlog 里面;传到备库应用的时候,相同 commit_id 的事务分发到多个 worker 执行;这一组全部执行完成后,coordinator 再去取下一批。
缺点:备库执行的时候要等待一组事务完全执行完后才能开始执行下一组,容易被大事务拖后腿。
MySQL 5.7 的并行复制策略
在 MariaDB 并行复制实现之后,官方的 MySQL5.7 版本也提供了类似的功能,由参数 slave-parallel-type 来控制并行复制策略:
配置为 DATABASE,表示使用 MySQL 5.6 版本的按库并行策略;
配置为 LOGICAL_CLOCK,表示的就是类似 MariaDB 的策略。不过,针对并行度做了优化。
MySQL 5.7 并行复制策略的思想是:
同时处于 prepare 状态的事务,在备库执行时是可以并行的;
处于 prepare 状态的事务,与处于 commit 状态的事务之间,在备库执行时也是可以并行的。
MySQL 5.7.22 的并行复制策略
5.7.22 版本里,MySQL 增加了一个新的并行复制策略,基于 WRITESET 的并行复制。相应地,新增了一个参数 binlog-transaction-dependency-tracking,用来控制是否启用这个新策略。这个参数的可选值有以下三种。
COMMIT_ORDER,根据同时进入 prepare 和 commit 来判断是否可以并行的策略。
WRITESET,表示的是对于事务涉及更新的每一行,计算出这一行的 hash 值,组成集合 writeset。如果两个事务没有操作相同的行,也就是说它们的 writeset 没有交集,就可以并行。
WRITESET_SESSION,是在 WRITESET 的基础上多了一个约束,即在主库上同一个线程先后执行的两个事务,在备库执行的时候,要保证相同的先后顺序。
参考资料:丁奇,MySQL实战45讲
部分内容来自网络,如有侵权请联系作者删除。




