5.6 引入多库并行主从复制,但并行只基于库(Schema)。实例存在多个 Schema,对从复制速度有比较大的帮助

5.6 并行复制架构

红框是并行复制关键

5.6 前 Slave 有I/O 和 SQL 两个线程

I/O 线程接收二进制日志,SQL 线程回放二进制日志

如果 5.6 开启并行复制,SQL线程变为 Coordinator 线程,主要负责以前两部分的内容:

  • 若可并行执行,选择 Worker 线程执行事务的二进制日志
  • 若不可以并行执行,如该操作是 DDL,或事务跨 Schema 操作,等所有 Worker 线程执行完成之后,再执行当前的日志

意味着 Coordinator 线程并不是仅将日志发送给 Worker 线程,自己也可以回放日志,但是所有可以并行的操作交付由 Worker 线程完成

Coordinator 线程与 Worker 是典型的生产者与消费者模型

基于 Schema 的并行复制存在两个问题

1) Crash Safe 不好做,可能后执行的事务由于并行复制的关系先完成执行,Crash 时,这部分处理逻辑比较复杂

5.6 引入 Low-Water-Mark ,希望借助于日志的幂等性来解决该问题,不过 5.6 的二进制日志回放还不能实现幂等性

2) 最为关键是这样并行复制效果并不高,实例仅有一个库,无法并行回放,甚至比原来单线程更差

单库多表比多库多表更常见

5.7 并行复制

Slave回放与主机是一致的,即 Master怎么并行执行的 Slave 上就怎样进行并行回放。不再有库的并行复制限制,对于二进制日志格式也无特殊的要求(基于库的并行复制也没有要求)

MySQL 官方原计划支持表级和行级并行复制,行级并行复制通过解析 ROW 格式的二进制日志的方式来完成。但最终出现的是在开发计划中称为:MTS: Prepared transactions slave parallel applier,引入MariaDB 思想,MariaDB 10 中出现

5.7 并行复制思想简单易懂,一言以蔽之:一个组提交的事务都是可以并行回放,因为这些事务都已进入到事务的 Prepare 阶段,则说明事务之间没有任何冲突(否则就不可能提交)


为兼容 5.6 基于库的并行复制,5.7 引入变量 slave-parallel-type,可配置的值有:

  • DATABASE:默认值,基于库的并行复制方式
  • LOGICAL_CLOCK:基于组提交的并行复制方式

如何知道事务是否在一组中,又是一个问题,原版的 MySQL 没提供

5.7 将组提交的信息存放在 GTID 中。那么如果用户没有开启 GTID 功能,即将参数 gtid_mode 设置为 OFF

5.7 又引入Anonymous_Gtid 的二进制日志 event 类型

SHOW BINLOG EVENTS in 'mysql-bin.000011';

| mysql-bin.000011 | 123 | Previous_gtids | 88 | 194 | f11232f7-ff07-11e4-8fbb-00ff55e152c6:1-2 |
| mysql-bin.000011 | 194 | Anonymous_Gtid | 88 | 259 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000011 | 259 | Query | 88 | 330 | BEGIN |
| mysql-bin.000011 | 330 | Table_map | 88 | 373 | table_id: 108 (aaa.t) |
| mysql-bin.000011 | 373 | Write_rows | 88 | 413 | table_id: 108 flags: STMT_END_F |

5.7 即使不开启 GTID ,事务开始前也会存 Anonymous_Gtid ,存着组提交信息

比原来二进制日志内容多了 last_committedsequence_number

mysqlbinlog mysql-bin.000011 |grep last_committed
#170607 11:24:57 server id 353306 end_log_pos 876350 CRC32 0x92093332 GTID last_committed=654 sequence_number=655
#170607 11:24:58 server id 353306 end_log_pos 880406 CRC32 0x344fdf71 GTID last_committed=655 sequence_number=656
#170607 11:24:58 server id 353306 end_log_pos 888700 CRC32 0x4ba2b05b GTID last_committed=656 sequence_number=657

没开启组提交的日志, binlog 中有两个参数 last_committedsequence_number

下一个事务在主库配置好组提交以后,last_committed 永远都和上一个事务的 sequence_number 是相等的。因为事务是顺序提交的

组提交模式的事务:

mysqlbinlog mysql-bin.000012|grep last_commit
#170609 10:11:07 server id 353306 end_log_pos 75629 CRC32 0xd54f2604 GTID last_committed=269 sequence_number=270
#170609 10:13:03 server id 353306 end_log_pos 75912 CRC32 0x43675b14 GTID last_committed=270 sequence_number=271
#170609 10:13:24 server id 353306 end_log_pos 76195 CRC32 0x4f843438 GTID last_committed=270 sequence_number=272

最后两个事务的 last_committed 相同,意味着这两个事务是作为一个组提交的,两个事务在 Perpare 阶段获取相同的 last_committed 而且相互不影响,最终是会作为一个组进行提交

这就是所谓的组提交。组提交的事务是可以在从机进行并行回放的

上述的 last_committedsequence_number 代表的就是所谓的 LOGICAL_CLOCK

启用并行复制

5.7 并行复制建立在组提交的基础上,主库上能够完成 Prepared 的语句表示没有数据冲突,就可以在 Slave 节点并行复制

 show global variables like '%group_commit%';

binlog_group_commit_sync_delay binlog_group_commit_sync_no_delay_count

master

  • binlog_group_commit_sync_delay

全局动态变量,单位微妙,默认 0,范围:0~1000000(1秒)

binlog 提交后等待延迟多少时间再同步到磁盘,默认0 ,不延迟

0 以上时,允许多个事务的日志同时一起提交,就是组提交。组提交是并行复制的基础,大于 0 就代表打开了组提交的功能

  • binlog_group_commit_sync_no_delay_count

全局动态变量,单位个数,默认 0,范围:0~1000000

等待延迟提交的最大事务数,如果上面参数的时间没到,但事务数到了,则直接同步到磁盘。若 binlog_group_commit_sync_delay 没有开启,则该参数也不会开启

slave

# 过多的线程会增加线程间同步的开销
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=4

直接在线启用也可以

stop slave;

set global slave_parallel_type='LOGICAL_CLOCK';
set global slave_parallel_workers=4;
start slave;

show variables like 'slave_parallel_%';
+------------------------+---------------+
| Variable_name          | Value         |
+------------------------+---------------+
| slave_parallel_type    | LOGICAL_CLOCK |
| slave_parallel_workers | 4             |
+------------------------+---------------+

检查Worker线程的状态

当前 Slave 的 SQL 线程为 Coordinator(协调器),执行 Relay log 日志的线程为 Worker(当前的 SQL 线程不仅起到协调器的作用,同时也可以重放 Relay log 中主库提交的事务)

从库能看到 4 个 Coordinator(协调器)进程

调优

master-info-repository 设 TABLE ,性能 50%~80% 提升

并行复制开启后对于 master.info 这个文件的更新将会大幅提升,资源的竞争也会变大

5.7 推荐将 master-info-repositoryrelay-log-info-repository 设置为 TABLE ,来减小这部分的开销

master-info-repository = table
relay-log-info-repository = table
relay-log-recovery = ON

并行复制监控

依旧可 SHOW SLAVE STATUS\G,但5.7 在 performance_schema 下多了以下这些元数据表,可以更细力度的进行监控:

use performance_schema;
show tables like 'replication%';
+---------------------------------------------+
| Tables_in_performance_schema (replication%) |
+---------------------------------------------+
| replication_applier_configuration           |
| replication_applier_status                  |
| replication_applier_status_by_coordinator   |
| replication_applier_status_by_worker        |
| replication_connection_configuration        |
| replication_connection_status               |
| replication_group_member_stats              |
| replication_group_members                   |
+---------------------------------------------+
8 rows in set (0.00 sec)