MySQL Group replication

双写

最近在研究异地多活双写的方案,自己实现Master-Master同步,实现是可以实现,但是有很多限制。目前双写主要有以下几个问题:

  1. 主键冲突。当两个Master自增的PK冲突的时候,就无法继续同步。解决方案有两个,一个是主键设置初始值和步长,还有一个是主键由业务来生成guid。
  2. 数据回环。数据回环的解决方案基本就是靠在事务开始结束打入标记来实现的,这个也不难,可以实现。
  3. 数据一致性。这个是最难解决的东西,主要由于binlog和业务执行产生了交叉,那么数据就会不一致。要么依赖timestamp来判别最新数据版本来避免覆盖,另一个是让一个机房成为主机房,数据产生冲突后以主机房的数据为准。但是无论哪个方案,都会有数据不一致的情况产生。所以业务规避同时写异地master的同一条记录是最稳妥的方案,但是这在机房异常切机房的情况下,会有一定的不可用时间。

研究了很多方案,都不如意,于是研究了下官方的方案。MariaDB支持Master-Master同步,但是由于不支持数据一致性检测,所以异地的两个库不能有相同的库名,所以在这种场景下不可用。MySQL官方在5.7.17后以插件的形式支持了Group replication,支持数据一致性检测。但是特性归特性,我们必须得了解底层的实现才能对整体有所把控。这方面的资料很少,所以自己在这里做了个总结。

Group replication

Group replication的特性看着非常吸引人,支持单master集群,多master集群,集群最多9个实例,支持在多master集群上同时读写数据。这应该是高可用最终的特性了。我们来仔细看一下,MySQL是通过何种方式来实现GR的。我们首先来解释一下几个名词:

  • Paxos。一个分布式场景下数据一致性的协议,初始的Paxos支持的是单leader发请求,所以MySQL使用的是它的变种算法。依赖该算法,可以实现分布式场景下多个节点数据一致,脑裂等各种复杂问题。
  • Write set。MySQL通过Write set来判别某个事务是否和别的事务产生冲突,从而回滚。

在多master模式下,理论上可以在任意master上操作,也就是存在多个master的并发问题,牵扯到并发,那么数据冲突是必须要解决的。我们来看一下,在GR模式下,提交事务的流程:

  1. 用户请求事务进行提交,那么在提交前,会收集当前事务的binlog、gtids_executed、操作的记录的PK信息等,并把这些信息提交给广播线程,用户线程休眠。
  2. 广播线程主要将事务提交信息通过一致性协议来广播到其余的master节点上,这里保证各个master会产生全局有序的事务提交信息,这是保证所有的master数据一致的根本要求。
  3. 广播成功后,会将该事务信息投递给notification线程来处理。该线程主要是进行对消息的dispatch,假设是事务信息,则会投递给apply线程。
  4. apply线程主要负责将冲突性检测,假设不冲突,则应用该事务。
  5. 唤醒用户线程,回复事务结果。

所以以上流程的核心为,并发提交的事务,最终会通过一致性协议来产生一个全局有序的事务列表,该列表会在所有的节点中存在,无论如何并发,所有的节点都会有一样顺序的事务提交记录,同时由apply线程进行certify和apply。

只要所有的事务全局有序,那么所有的节点按照同一个顺序进行应用,整个集群肯定可以保证一致性。剩下的就是冲突检测了。上面说过,在commit之前,事务提交记录有以下几个用于冲突判断的信息:

  • 操作的记录主键
  • 操作时候数据的版本,依赖gtids_executed

假设在数据版本号一致的情况下,多个master节点同时更新一行数据,那么后提交的事务会被回滚,先提交的事务会被接受。

假设在数据版本号不一致的情况下,多个master节点同时更新一行数据,假设版本号旧的先执行,再执行新的版本,那么不会冲突,因为新版本的数据已经包含了老的,是在老的基础上执行而来;反之则会丢弃老的事务。

共 0 条回复
暂时没有人回复哦,赶紧抢沙发
发表新回复

作者

sryan
today is a good day