MySQL · 特性分析 · 5.6并行复制事件分发机制
最后更新于:2022-04-01 10:38:42
## 并行复制相关线程
在MySQL 5.6并行复制中,当设置`set global slave_parallel_workers=2`时,共有4个复制相关的线程,如下:
~~~
+----+-------------+------+-------+---------+------+------------------------------------------------------------------+------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO |
+----+-------------+------+-------+---------+------+------------------------------------------------------------------+------+
| 23 | system user | | NULL | Connect | 3 | Waiting for master to send event | NULL |
| 24 | system user | | mysql | Connect | 3 | Slave has read all relay log; waiting for the slave I/O thread t | NULL |
| 25 | system user | | NULL | Connect | 3 | Waiting for an event from Coordinator | NULL |
| 26 | system user | | NULL | Connect | 3 | Waiting for an event from Coordinator | NULL |
+----+-------------+------+-------+---------+------+------------------------------------------------------------------+------+
~~~
其中第一个为IO线程,负责从主库拉取binlog到备库并存为relay log;
第二个为分发线程,负责解析relay log,并将解析后的事件分发给worker线程处理;
其余两个为worker线程负责处理分发后的事件,类型非并行复制时的sql线程。
## 并行复制并发策略
目前RDS MySQL并行复制是以表级别进行分发的,即同一时刻,同一个表相关的操作只能在同一个worker线程中进行。
考虑两个事务,分别对表进行insert
~~~
trx1:
begin;
insert into t1 values(1);
comit;
trx2:
begin;
insert into t2 values(1);
comit;
~~~
那么这两个事务可能分别在两个worker中并行执行。
有些特殊情会影响worker的并发执行:
* 并行退化为串行的情况
* DDL语句串行处理(RDS MySQL正在优化DDL并行处理)
* binlog切换事件需串行处理
* 有外键关系的表需串行处理
* 并行等待的情况
当一个事务中包含多个表时,如下:
~~~
trx3:
begin;
insert into t1 values(3);
insert into t2 values(3);
comit;
~~~
如果当前worker1正在执行t1相关的事务,worker2正在执行t2相关的事务,那么分发线程在分发trx3的t2的事件时必须等待worker2的t2相关的事务执行完成。
## 并行复制worker分配
假设,worker线程正在执行的情况如下:
~~~
worker 1: trx1: insert t1
worker 2: trx2: insert t2; trx3: insert t3;
~~~
然后分发线程再来一个事务trx4:
~~~
trx4: insert t4;
~~~
分发线程该分配给哪个worker呢?
分配线程分配会分配给最空闲的worker(`get_least_occupied_worker`);
这里最空闲是指worker当前正在执行的事务涉及的表数越少越空闲。
worker1正在执行的事务涉及的表数为1,而worker2正在执行的事务涉及的表数为2,因此trx4会分配为worker1;
表和worker存在一一对应关系,为了快速找到表对应的worker,哈希表(`mapping_db_to_worker`)存储了这种映射关系。同时为了控制哈希表过大导致占用较多内存或哈希冲突,系统严格控制了哈希表的大小,不能超过16(硬编码`mts_partition_hash_soft_max`),当超过16时,会将当前没有执行的表从哈希表驱逐出去。
在表较多情况下,哈希表大小设为16显得过小,可能会频繁驱逐表,频繁新建哈希键值对的情况。
## 优化
1. 表级并行复制下,哈希表的大小16(硬编码`mts_partition_hash_soft_max`)过小,应设为动态可调;
2. 分配线程分配会分配给最空闲的`worker(get_least_occupied_worker)`。
考虑如下情况:
~~~
worker 1: t1 1000个事务
worker 2: t2 10个事务 t3 10 个事务
~~~
当前worker1比worker2要繁忙,而按照当前正在执行的事务涉及的表数越少越空闲的原则,新来的事务(比如insert t4)会分配给worker1,这是不合理的。
因此,空闲的标准应改为当前正在执行的事务数越少越空闲,这样新来的事务会分配给worker2。