0%

MySQL复制:并行复制

基于组提交的并行复制

在MySQL复制运行过程中,可能由于主从机器性能差异、大事务、大表DDL等原因导致主从复制延迟。并且由于SQL线程是单线程串行执行,当主节点写入压力较大时也非常容易造成复制延迟,针对这种情况,MySQL5.6提供了并行复制功能。其中把SQL线程分为coordinator_thread和worker,coordinator线程主要负责判断是否可并行执行,然后选择Worker线程执行事务的二进制日志,如果是DDL或是事务跨schema这种不可并行执行的,则等待worker线程执行完成后再执行当前日志。

并行复制维护着一张hash表,其记录了每个数据库有多少事务分发出去,执行事务的worker线程,因此分配线程是以数据库名分发的,当一个实例只有一个一个schema时,并行复制并不会带来有效提升。

随后,MySQL5.7推出了基于组提交的并行复制机制,即一个组提交的事务是可以并行回放到从库,原理是基于锁冲突检测,因为事务进入到prepare阶段,就说明事务之间没有冲突。组提交的信息存在binlog中,如果未开启GTID在5.7中提供了一种Anonymous_gtid的二进制日志event_type

1
2
3
4
5
6
$ mysqlbinlog mysql-bin-3306.000004 | grep last_committed
#160726 23:40:09 server id 1 end_log_pos 302010138 CRC32 0xf5950910 Anonymous_GTID last_committed=1566 sequence_number=1567
#160726 23:40:09 server id 1 end_log_pos 302010676 CRC32 0xb9b3038c Anonymous_GTID last_committed=1566 sequence_number=1568
#160726 23:40:09 server id 1 end_log_pos 302011214 CRC32 0x30f1ec4e Anonymous_GTID last_committed=1566 sequence_number=1569
#160726 23:40:09 server id 1 end_log_pos 302011752 CRC32 0x44443efe Anonymous_GTID last_committed=1566 sequence_number=1570
#160726 23:40:09 server id 1 end_log_pos 302012290 CRC32 0x79fe16ec Anonymous_GTID last_committed=1566 sequence_number=1571

如果事务具有相同的last_committed,则表示在同一个组内,可以进行并行回放。

开启组提交并行复制需要设置以下参数:

  • slave_parallel_workers:worker线程数
  • slave_parallel_type:并行复制类型,默认为5.6中的DATABASE,组提交模式需要设置为LOGICAL_CLOCK

此外,还有两个参数可以用于控制组提交的频率:

  • binlog_group_commit_sync_delay:表示binlog提交后等待延迟多少时间再同步到磁盘,单位为微妙,默认值为0。设置延迟可以让多个事务在同一时刻提交,提高binlog组提交的并发率和效率,从而提高slave的吞吐量
  • binlog_group_commit_sync_no_delay_count:表示在等待上面参数时,如果满足事务量,则结束等待直接提交。需要设置事务数,默认为0

Tips:如果需要强制slave上的binlog提交顺序和master一样,保证GTID的顺序,可以设置slave_preserve_commit_order,前提是开启了logical_clock和binlog(开启该参数对性能有一点影响)

ERROR 1864

开启logical_clock后可能会遇到如下错误

1
Cannot schedule event Write_rows, relay-log name ./mysql-relay-bin.001304, position 416228895 to Worker thread because its size 16777357 exceeds 16777216 of slave

主要是因为从库slave_pending_jobs_size_max参数小于主库max_allowed_packet,需要将其设置大于主库max_allowed_packet

基于write set并行复制

在MySQL5.7.22中,MySQL又增加了一个并行复制策略:基于write set的并行复制。write set的思想在于不同事务的不同记录不重复,则都可以在从机上并行回访,达到一种按行分发的模式,并行性能更上一步。

参数binlog-transaction-dependency-tracking控制该策略,有三个可选值:

  • COMMIT_ORDER:根据同时进入prepare和commit来判断是否可以并行的策略
  • WRITESET:对于事务涉及的每一行,计算出hash值,组成一个writeset集合,当两个事务没有操作相同的行,它们的writeset就不存在交集,可以并行处理
  • WRITESET_SESSION:在WRITESET基础上添加了一个约束,在主库上同一个线程先后执行的两个事务,在从节点执行时要保证相同的先后顺序

如果想要使用writeset,需要在主库设置下列两个参数:

1
2
transaction_write_set_extraction=XXHASH64
binlog_transaction_dependency_tracking=WRITESET

writeset集合中的每一个元素都是hash值,hash值和transaction_write_set_extraction参数的算法有关,hash值作为唯一标识是通过”db+table+index+value”计算出来的,如果表上还存在唯一索引,insert对应的writeset就需要多增
加一个hash值。每行数据的具体格式为:

主键/唯一键 | 分隔符 | 库名 | 分隔符 | 库名长度 | 表名 | 分隔符 | 表名长度 | 键字段 | 分隔符 | 长度
– | – | – | – | – | – | – | – | –| – |