天天看点

MySQL并发复制系列三:MySQL和MariaDB实现对比

经过上两篇关于mysql/mariadb 的binary log group commit的发展历程和enhanced multi-threaded slave的介绍,相信大家对mysql 基于binay log 的replication的原理以及为了解决主备数据复制延迟问题而引入的enhanced multi-threaded slave 功能,支持从库多线程并发回放主库提交的事务有了更深入的了解。同时为了更好的发挥mysql 5.7/mariadb 10 并发复制的性能,两个版本都在主库binary log group commit的阶段做了更加深入的优化。

无论是mysql还是mariadb在binary log group commit优化的目的都是:使高并发下的事务尽可能的在同一个时间点提交,然后用一次fsync()的操作将这一组的binary log缓存的数据写入磁盘。当并发事务可以在同一个时间提交,说明每个线程所执行的事务之间没有锁冲突(如果有锁冲突,并发的事务将无法在同一个时刻提交),那么意味着这一组并发提交的事务在slave机器上能并发重放主库提交的事务,所以我们只需要在master机器对二进制日志进行group commit的时候标记上组提交相关信息,slave机器就可以安全的并发执行主库提交的事务。

我们来看一个例子:

事务t1、t2(start transaction)开始事务,落后于事务t3、t4的(start transaction)开始时间,但是这一组事务都在c(commit)时间点提交事务,所以这一组事务(t1、t2、t3、t4)将在master机器上进行binary log group commit,然后该二进制日志推送到slave机器上时可以并发执行这一组被标记的事务。

MySQL并发复制系列三:MySQL和MariaDB实现对比

原理:

从上面的例子可以看出,并发线程执行不同的事务只要在同一时刻能够commit(说明线程之间没有锁冲突),那么master节点就可以将这一组的事务标记并在slave机器上安全的进行并发重放主库提交的事务。所以尽可能的使所有线程能在同一时刻提交可以极大的提高slave机器并发执行事务的数量使主备数据同步。

在上一篇文章提到过:mysql/mariadb开启binary log日志后使二进制日志写入顺序和存储引擎提交顺序保持一致,binary log group commit分为三个过程:

MySQL并发复制系列三:MySQL和MariaDB实现对比

图1: binary log group commit 三个阶段

在 flush stage:所有已经注册线程都将写入binary log缓存

在sync stage :binary log缓存的数据将会sync到磁盘,当sync_binlog=1时所有该队列事务的二进制日志缓存永久写入磁盘

在 commit stage:    leader根据顺序调用存储引擎提交事务。

那么为了使更多的并发线程事务能够视为在同一个时刻commit即在sync阶段(调fsync()把binary log文件系统缓存日志永久刷入磁盘文件)master机器标记并发提交的事务为同一组事务的信息写入binary log日志中。我们可以在flush stage将注册为leader的线程带领更多的follower线程到sync stage进行一次fsync()的操作,来增加binary log group commit的数量。

如下图:

当前mysql/mariadb数据库实例上运行三个线程分别提交t1、t2、t3事务,t1事务的线程率先提交进入第一阶段flush stage队列,发现该队列是空队列故注册成leader,与此同时t2事务进入flush stage成为该队列的follower等待leader调配,事务t1的leader带领t2事务进入sync stage进行一次fsync()操作那么t1、t2在binary log进行一次group commit。

在二进制日志内标记了这一组事务。之后t3线程的事务随后进入了binary log提交的过程。

MySQL并发复制系列三:MySQL和MariaDB实现对比

图2: 组提交过程

mariadb 10通过@@binlog_commit_wait_count and @@binlog_commit_wait_usec 两个参数设置,既事务commit阶段的时候至少等binlog_commit_wait_usec毫秒直到有binlog_commit_wait_count个数时进行一次组提交,来提高每组事务中的事务数量,并可以通过查询状态变量@@binlog_commit和@@binlog_group_commit来查参数来查看当前binary log group commit比例。

mysql5.7通过引入 binlog_group_commit_sync_delay和 binlog_group_commit_sync_no_delay_count参数即提高binary log组提交并发数量,既mysql等待binlog_group_commit_sync_delay毫秒的时间直到binlog_group_commit_sync_no_delay_count个数时进行一次组提交。

实现:

binary log group commit在mysql 5.7和mariadb 10 中是默认开启不需要配置任何信息,且在binary log中标记的组提交信息依赖于gtid,而mysql和mariadb的gtid组成和实现方式不一样,这里我们简单梳理下。

在mysql 5.7版本由于binary log group commit是默认开启的,所以即使你不开启gtid_mode在配置文件中,binary log的内容中同样也有gtid 信息只不过标记的信息是"anonymous"

>    show binlog events in 'mysql-bin.000004';截取一段信息

1.  ...............

| mysql-bin.000004 | 3571 | anonymous_gtid |     15112 |        3636 | set @@session.gtid_next= 'anonymous'          |

2.  | mysql-bin.000004 | 3636 | query          |     15112 |        3712 | begin                   |

3.  | mysql-bin.000004 | 3712 | rows_query     |     15112 |        3763 | # insert into t1 () values ()                 |

4.  | mysql-bin.000004 | 3763 | table_map      |     15112 |        3807 | table_id: 108 (db2.t1)                        |

5.  | mysql-bin.000004 | 3807 | write_rows     |     15112 |        3847 | table_id: 108 flags: stmt_end_f               |

6.  | mysql-bin.000004 | 3847 | xid            |     15112 |        3878 | commit /* xid=33 */                           |

.................

>     mysqlbinlog -vvv mysql-bin.00004 | less

1.  #151231 14:34:03 server id 15112  end_log_pos 2408 crc32 0x5586fe71     anonymous_gtid last_committed=6 sequence_number=8

2.  set @@session.gtid_next= 'anonymous'/*!*/;

3.  # at 2408

4.  #151231 14:34:03 server id 15112  end_log_pos 2484 crc32 0x748efb17     query   thread_id=11    exec_time=0     error_code=0

5.  set timestamp=1451543643/*!*/;

6.  begin

7.  ..

mariadb的gtid同样也是默认开启且gtid是由domain id、server id和transaction sequence number组成:

MySQL并发复制系列三:MySQL和MariaDB实现对比

图3 mariadb gtid组成

>    show binlog events in 'mysql-bin.000003';截取一段信息

1.  .......

| mysql-bin.000003 |  335 | gtid              |     15102 |         377 | begin gtid 0-15102-64139                      |

2.  | mysql-bin.000003 |  377 | table_map         |     15102 |         434 | table_id: 18 (test.sbtest1)                   |

3.  | mysql-bin.000003 |  434 | write_rows_v1     |     15102 |         657 | table_id: 18 flags: stmt_end_f                |

4.  | mysql-bin.000003 |  657 | xid               |     15102 |         688 | commit /* xid=16 */                           |

5.  | mysql-bin.000003 |  688 | gtid              |     15102 |         732 | begin gtid 0-15102-64140 cid=20               |

6.  | mysql-bin.000003 |  732 | table_map         |     15102 |         789 | table_id: 19 (test.sbtest6)                   |

7.  | mysql-bin.000003 |  789 | write_rows_v1     |     15102 |        1012 | table_id: 19 flags: stmt_end_f                |

8.  | mysql-bin.000003 | 1012 | xid               |     15102 |        1043 | commit /* xid=20 */                           |

9.  | mysql-bin.000003 | 1043 | gtid              |     15102 |        1087 | begin gtid 0-15102-64141 cid=20               |

10. | mysql-bin.000003 | 1087 | table_map         |     15102 |        1145 | table_id: 20 (test.sbtest12)                  |

11. | mysql-bin.000003 | 1145 | write_rows_v1     |     15102 |        1368 | table_id: 20 flags: stmt_end_f                |

12. | mysql-bin.000003 | 1368 | xid               |     15102 |        1399 | commit /* xid=21 */                           |

......

>    mysqlbinlog -vvv mysql-bin.00003  | less

1.     .......

2.     # at 1754

3.  #160104 15:16:46 server id 15102  end_log_pos 1798 crc32 0x26104c0b gtid 0-15102-64143 cid=20 trans

4.  /*!100001 set @@session.gtid_seq_no=64143*//*!*/;

5.  begin

6.  /*!*/;

7.  # at 1798

8.  #160104 15:16:46 server id 15102  end_log_pos 1856 crc32 0x2c994f5a     table_map: `test`.`sbtest12` mapped to number 20

9.  # at 1856

10. #160104 15:16:46 server id 15102  end_log_pos 2079 crc32 0x02b5a694     write_rows: table id 20 flags: stmt_end_f

11.

12.  binlog '

13.  .........

结论:

mysql 5.7 / mariadb 10的parallel replication都是基于主库上binary log group commit。

mysql:  主库并发提交的事务group commit写入binary log日志中,当事务被标记的 last_committed=n的值相同时(通过binlog_group_commit_sync_delay、 binlog_group_commit_sync_no_delay_count参数设置提高并发事务数量),可以在slave节点并发回放主库提交的事务。

mariadb: 主库并发提交的事务group commit写入binary log日志中,当事务被标记的 cid=n 的值相同时(通过 binlog_commit_wait_count、binlog_commit_wait_usec参数设置提高并发事务数量),可以在slave节点并发回放主库提交的事务。

<b>本文来自云栖社区合作伙伴“dbgeek”</b>