25 | MySQL主从延迟分析以及HA保障(柯南版的中篇)
作者:互联网
一、前置背景
上一篇中讲到主从延迟场景对于从库的影响一般是分钟级别的,备库恢复之后都可以追上来,但是第四点如果备库执行日志的速度低于主库生成日志的速度,可能会导致小时级别的延迟。
--这篇是个重点,来到了面试可以装逼的环节。PS:在大神面前估计装不了。
二、主备库并行复制能力
2.1.主库上并发度受什么影响?备库上日志的执行是单线程还是多线程的?
-
在主库上,影响并发度的原因就是各种锁了。由于 InnoDB 引擎支持行锁,除了所有并发事务都在更新同一行(热点行)这种极端场景外【顾名思义秒杀场景】,它对业务并发度支持很友好。
-
在官方的 5.6 版本之前,MySQL 只支持单线程复制,由此在主库并发高、TPS 高时就会出现备库sql thread线程更新数据 (DATA) 的严重延迟。
2.2.sql thread的多线程复制原理是怎么样的?
1)大致图解如下
⭐️说明:coordinator 就是原来的 sql_thread, 不过现在它不再直接更新数据了,只负责读取中转日志和分发事务。真正更新日志的,变成了 worker 线程。而 work 线程的个数,就是由参数 slave_parallel_workers 决定的。
⚠️:经验把这个slave_parallel_workers值设置为 8~16 之间最好(32 核物理机的情况),毕竟备库还有可能要提供读查询,不能把 CPU 都吃光了。
2)所以,coordinator 在分发的时候,需要满足以下这两个基本要求:
-
不能造成更新覆盖。这就要求更新同一行的两个事务,必须被分发到同一个 worker 中。
-
同一个事务不能被拆开,必须放到同一个 worker 中。 | PS:这里是指事务迟早要commit,但是两个worker是两个线程,没办法约好“同时提交”,这样就有可能出现一个先提交一个后提交。虽然最终的结果是主备一致的,但如果表 a 执行完成的瞬间,备库上有一个查询,就会看到这个事务“更新了一半的结果”,破坏了事务逻辑的隔离性。
2.3.如果自己实现并行复制策略应该怎么做?有什么优缺点?
分为两种策略:
-
1)按表并行复制,每个 worker 线程对应一个 hash 表,用于保存当前正在这个 worker 的“执行队列”里的事务所涉及的表。hash 表的 key 是“库名. 表名”,value 是一个数字,表示队列中有多少个事务修改这个表。例如,worker中有db1.t1 : 4 和 db2.t2 : 1。缺点并行度低,热点行问题就变成了单线程。
2)按行并行复制,如果两个事务没有更新相同的行,它们在备库上可以并行执行。显然,这个模式要求 binlog 格式必须是 row。hash表的key是“库名.表名.主键.唯一键名字.唯一键值”。缺点:耗IO和内存。
2.4.MySQL5.6并行复制策略是怎么做的?
-
按照库维度进行并行。
2.5.MariaDB的并行复制策略依据是什么?分为那四步?好处是什么?缺点是什么?
-
利用了组提交的特性。
-
1)在一组里一起提交的事务有一个相同的commit_id,下一组就是 commit_id+1。2)commit_id直接写到binlog里面。3)相同commit_id的事务分发到多个worker。4)这一组全部执行完之后,coordinator再去取下一批。
-
模拟了主库的并行模式,而不是分析binlog拆解到worker上。
-
在备库上执行的时候,要等第一组事务完全执行完成后,第二组事务才能开始执行,这样系统的吞吐量就不够。
2.5.1.那组提交有什么特性呢?
1)能够在同一组里提交的事务一定不会修改同一行。那怎么保证修改同一行的事务执行顺序呢?答:如果修改同一行commit的时候就会被锁住,等待锁的事务会等待不会进入commit状态。
2)主库上可以并行执行的事务,备库上也一定是可以并行执行的。
2.6.MySQL5.7的并行复制策略是怎么做的?LOGICAL_CLOCK具体方式什么?该方式具有什么优化策略?
-
由参数 slave-parallel-type 来控制并行复制策略:配置为 DATABASE,表示使用 MySQL 5.6 版本的按库并行策略;配置为 LOGICAL_CLOCK,表示的就是类似 MariaDB 的策略。
-
设置为
LOGICAL_LOCK
则会采用基于GroupCommit的并行回放,同一个Group内的事务将会在Slave上并行回放。MySQL 5.7 版本在产生 Binlog 日志时会有两个特殊的值记录在Binlog Event中,last_committed
和sequence_number
, 其中 last_committed 指的是该事务提交时,上一个事务提交的编号,sequence_number 是事务提交的序列号,在一个Binlog文件内单调递增。如果两个事务的last_committed
值一致,这两个事务就是在一个组内提交的。 -
“所有处于 commit”状态的事务可以并行。事务处于 commit 状态,表示已经通过了锁冲突的检验了。优化策略:在两阶段提交过程中,只要保证到达了redo log prepare阶段,就表示事务已经通过锁冲突的检验了。所以,就可以通过设置binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count参数来拉长 binlog 从 write 到 fsync 的时间,从而增加prepare阶段的事务。
2.7.MySQL5.7.22的并行复制策略是怎么做的,每个参数值的具体作用是什么?
-
新增了一个参数 binlog-transaction-dependency-tracking:
COMMIT_ORDER,表示的就是前面介绍的,根据同时进入 prepare 和 commit 来判断是否可以并行的策略。
WRITESET,表示的是对于事务涉及更新的每一行,计算出这一行的 hash 值,组成集合 writeset。如果两个事务没有操作相同的行,也就是说它们的 writeset 没有交集,就可以并行。hash 值是通过“库名 + 表名 + 索引名 + 值”计算出来的
WRITESET_SESSION,是在 WRITESET 的基础上多了一个约束,即在主库上同一个线程先后执行的两个事务,在备库执行的时候,要保证相同的先后顺序。
三、疑问点
-
group commit分为几步,每一步做什么?
四、课后题
假设一个 MySQL 5.7.22 版本的主库,单线程插入了很多数据,过了 3 个小时后,我们要给这个主库搭建一个相同版本的备库。这时候,你为了更快地让备库追上主库,要开并行复制。在 binlog-transaction-dependency-tracking 参数的 COMMIT_ORDER、WRITESET 和 WRITE_SESSION 这三个取值中,你会选择哪一个呢?
五、评论区
⚠️:并行策略,当同一组中有3个事务,它们都对同一行同一字段值进行更改,而它们的commit_id相同,可以在从库并行执行,那么3者的先后顺序是怎么保证不影响该行该字段的最终结果与主库一致?
--大部分人都会有这个问题
答:对同一行的修改,第一个拿到行锁的事务还没提交前,另外两个会被行锁堵住的,这两个进入不了commit状态。所以这三个的commit_id不会相同的
标签:主库,25,事务,备库,柯南版,并行复制,worker,MySQL,commit 来源: https://blog.csdn.net/hxy_lbj/article/details/117199525