MySQL复制一致性问题探索(二)-MGR

目录

一、前言

二、MGR介绍

三、MGR复制原理

四、MGR复制过程

五、深入理解MGR事务复制

总结

参考资料


一、前言

   MySQL作为现在很热门的数据库,由于其开源性,在互联网公司受到了很大的青睐,随着对数据库安全可控的考虑,在银行、政府、航空等行业已经开始较大范围的推广和使用,其中如何保证数据一致性是在使用中经常会被问到的问题。

上篇文章分析了MySQL主从复制在特殊场景下会出现数据不一致及如何解决、规避,正是因为基于传统异步复制和半同步复制的缺陷——数据的一致性问题无法保证,MySQL官方在2016年12月 第一个GA版本5.7.17正式推出组复制(MySQL Group Replication,简称MGR),本篇文章将详细介绍MGR是如何保证数据一致性的。

二、MGR介绍

组复制是MySQL官方开发的一个开源插件,一个MySQL数据库就是其中一个组员,由MGR做统一的集群管理,解决了原主从模式下故障后需要人工或辅助工具介入的问题,提供了高可用的集群自管理能力。同时它是一种可用于实现容错系统的技术,只要确保多数组员存活就可以继续对外提供服务。最重要的是,它解决了因节点故障或网络问题导致的数据不一致问题,这也是本文讨论的重点,图1是简单的一个拓扑图。

MySQL复制一致性问题探索(二)-MGR_第1张图片 图1

三、MGR复制原理

组复制是一组MySQL Server集群,每个Server都有自己完整的数据副本(shard-nothing复制方案),它们之间数据同步是通过消息进行传递和交互的。相比较主从复制,组复制依然传输Binlog Event,但是并没有采用之前的传输机制,而是创建了独立的通讯通道,通信层提供了原子消息(atomic message)和完全有序信息(total order message)交互、故障检测(脑裂)的保障机制。对比主从简单的点到点、无保证的日志复制传输发生了本质的变化。该技术的核心正是由Paxos算法实现的,它也是实现多主复制的核心技术。这也是为什么组复制能保证数据一致性的关键所在。

在多主模式下,复制组内每个节点都可以独立执行事务,而读写事务需要在组内的其他成员协调之后才可以提交。因此,当一个事务准备提交时,会自动在组内进行原子性的广播,所有节点要么接受,要么不接受事务。组内成员会按照之前发送事务的顺序收到该广播消息(事务),并以同样的顺序重演这些事务日志,最终保证了组内数据完全一致的状态。后文会有详细的事务复制过程讲解。

但是,在不同组成员上并发地执行事务有可能存在资源争用现象。如不同成员并发更新同一行数据。这个时候需要用到组复制另外一个非常重要的功能冲突检测。根据冲突检测判断,按照顺序,第一次提交到所有组成员上的事务继续执行提交(成功),第二次提交到所有成员的事务将被终止(失败),第二次事务在发起原始组成员上执行回滚,在其他组成员将会被删除(丢弃,不会写入到relay log中),后文会有详细的事务认证过程讲解。

四、MGR复制过程

组复制有两种模式:单主模式和多主模式。在单主模式下,组复制具有自动选主功能,每次只有一个Server成员接受写操作。在多主模式下,所有的 server 成员都可以同时接受写操作。两种模式的复制过程是一样的,但也有不同之处,下面介绍一下组复制的复制过程。

组复制虽然也是传送Binlog Event,但并不像异步复制那样是简单的点到点传输。MGR在传输数据时,使用了Paxos协议,具体为Paxos的xcom组件。它的核心工作就是就是对所有数据包进行汇聚和排序,并且至少保证半数以上节点收到才会认为消息发送成功。在一致性协议层(图2红色标注的部分)实现了原子消息和全局有序消息,保证了数据传输的原子性(要么成功,要么失败)和一致性。前文已经提过,它是保证数据一致性的关键。

MySQL复制一致性问题探索(二)-MGR_第2张图片 图2

MGR由若干个成员共同组成一个复制组,一个事务的提交,必须经过组内大多数成员(N / 2 + 1)确认收到消息后,才能进行决议并提交。如图2所示,由3个成员组成一个复制组,Consensus层为一致性协议层。在事务提交过程中,发生组间通讯,由2个节点确认收到消息后,并进行决议(certify)通过这个事务,才能够最终得以提交并响应。

从图2可以看出对比传统的主从复制,增加了一致性协议层和冲突认证,前文多次提过,这些是保证数据一致性和多主复制的关键所在。

单主和多主的复制过程是一样的, 但在单主模式下,冲突检测是关闭的,备节点所有事务均可提交,而多主是必须要开启的。

多主模式虽然可以多点写入,但对比单主模式有很多的限制及性能问题,由于不是本文讨论重点,这里不做展开。

从组复制原理上看,当主节点事务提交时,从节点上可能还未重放该事务对应的Binlog,因此MGR仍属于异步复制。但是在数据层MGR基于Paxos实现了数据的强一致,或者说多数派的强一致,这是毋庸置疑的。

一致性就是数据保持一致,在分布式系统中,可以理解为多个节点中数据的值是一致的。下面说一下对于强一致的理解:

1)主库需要等待从库的确认,确保从库已经收到写入操作,那么复制是同步的,即强一致性。

2)强一致性可以保证从库有与主库一致的数据。如果主库突然宕机,我们仍可以保证数据完整。但如果从库宕机或网络阻塞,主库就无法完成写入操作。

3)强一致性可以理解为在任意时刻,所有节点中的数据是一样的。同一时间点,你在节点A中获取到key1的值与在节点B中获取到key1的值应该都是一样的。

对于第三点的理解,它应该属于读一致性,或者说客户端强一致性,而本文说的数据一致性都是服务器端的,也就是保证数据层的强一致性。这点我之前对强一致理解也是一直把两个强一致性放在一起,但随着不断的深入理解后,在表述的时候做了区别对待,这样更便于理解,所以本文前面提到的都是数据一致性,而没有刻意强调强一致。

需要说明,MGR在8.0.14后推出了读一致性,通过group_replication_consistency这个参数控制,实现了客户端和服务器端的都满足强一致,是不是很厉害!但由于其性能等问题,就如同Oracle最大保护模式,实际生产很少被用到一样,使用的并不广泛。由于不是本文讨论的重点,这里不再展开。

五、深入理解MGR事务复制

前文都是对MGR如何实现了数据层、服务器端的强一致的探索研究。讲到这里基本把MGR是如何保证数据一致性的原理说明白了。下面的部分是更加深入的讲解一下MGR事务的复制过程,感兴趣的读者可以继续阅读。

首先我们理解下面的知识点:

1.在多主模式下,MGR采用的乐观锁机制,不同主库的事务都可以先执行,只有在提交的时候才会做事务冲突验证;

2.在组复制中要提交事务,组内的大多数成员必须就全局事务序列中给定的事务顺序达成一致。如果存在网络分区,导致出现了组成员无法达成一致意见,系统会发生阻塞(不会继续向前执行)。

3.对于任何读写事务,都是由组来决定它是否可以提交,而不是由发起事务提交的原始组成员单方面决定。如果是只读事务,则不需要在组内进行协调,可以立即提交。

单主模式复制过程和多主模式一样,但关闭了事务认证模块,相对比较简单,所以下面将以多主模式、且并发更新同一行数据相对复杂的事务场景为例,深入描述事务的执行过程。

图3,DB3的内部事务执行过程和其他节点原理是一样的,此图不再显示。前面图2提到的一致性协议层,就是图3的通讯模块,红色圈标注,冲突认证为本图的全局事务认证模块,黑色圈标注。

MySQL复制一致性问题探索(二)-MGR_第3张图片 图3

1.如图3,T1、T2、T3事务并发执行提交

2.首先进入prapare阶段,然后各自将事务信息(主键信息、gtid_executed值和Binlog Event)发送给通讯模块

3.通讯模块基于Paxos协议,对事务进行汇聚,排序发送给DB1、DB2、DB3的通讯模块,当超过2个以上的(包括自己)收到信息并回应后,通讯模块才会把事务信息发送给全局认证模块

3.1Paxos协议的核心工作就是对所有数据包进行汇聚和排序,如图4,Paxos进行了三次TCP通讯:

1)发送数据库包给其他成员。

2)其他通讯模块回应收到的通讯包。

3)超过半数(包括它自己)回应后,发送消息告诉所有节点,这个包同步成功,之后把这个包发给全局认证模块。

MySQL复制一致性问题探索(二)-MGR_第4张图片

MySQL复制一致性问题探索(二)-MGR_第5张图片 图4

事务T1,T2,T3分别并发在DB1,DB2,DB3上进行提交,通讯模块基于Paxos协议进行汇聚、排序后发送给全局事务认证模块,确保每个数据库具有相同的数据包且顺序是一致的,如图4按照T1,T2,T3的顺序发送给全局认证模块。

4. 全局认证模块核心是判断事务是否存在冲突,哪些是同时修改了同样数据的事务。

1)事务T1,T2,T3分别在DB1,DB2,DB3上同时更新t1表的同一行,此时在三个数据库上gtid_executed的值是一样的,如图5:

MySQL复制一致性问题探索(二)-MGR_第6张图片 图5

首先T1事务先被认证,此时的gtid_executed事务id为50,小于当前执行值100,可以被执行,认证通过,并把执行后的t1表id=5的gtid _executed事务id更新为101。同时本地(db1)写入Binlog日志,并返回成功,另外两个节点(DB2,DB3)会写入到 relay log并被应用。假如T1事务没有被认证成功,那么会在DB1数据库报错并会退,在另外两个节点丢弃。如图3 T1的失败流程。

这时继续认证事务T2,很明显,事务T2的gtid_executed事务id(100)已经小于最新的值(101),所以无法执行。T3同样存在同样的问题,如图6,T2和T3 这两个事务会在自己本地执行的数据库节点回退并报错,其他远程数据库上丢弃。

MySQL复制一致性问题探索(二)-MGR_第7张图片 图6

以上比较详细介绍了MGR事务的同步过程,其实内部还隐藏着很多的技术细节,在这里不做展开。有钻研精神的同学可以通过阅读MySQL源码获取更多技术细节,本文本着通俗易懂的精神给大家做了介绍,希望对大家有所帮助。

上面讲解的复制过程是一个复制的特殊场景,多主+并发+更新同一行数据,当对这个场景有了认识后,其他的普通场景就更加容易理解了。同时在生产中如果频繁出现并发更新同一行的情况,需要应用查看一下自己的逻辑是否合理,或考虑只在某一个节点执行,避免冲突发生。

希望大家能对MGR的复制过程,及如何确保数据复制一致性的有了更加清晰的认识。

总结

MGR的出现,解决多年困扰的Mysql数据库复制一致性问题,打通了最后一道技术壁垒,满足了金融等领域对数据一致性高的要求。同时在集群管理、高可用上都有很大的优势,而且它提供的多写模式给真正意义上的数据双活提供了方案。

综合上面的优势,MGR必定将成为未来的趋势。MGR从2016至今做了很多的版本更新,现最新GA版本是2020年4月发布的8.0.20,这么多年的迭代中修复了很多BUG,基本趋于稳定,我们计划将于今年下半年进行引进并尝试推广。

写文章也是一次很好的学习过程,砥砺前行,不忘初心。感谢团队小亮、小海同学一起的讨论学习。后续我们将推出国产数据库介绍系列,对我们研究过、POC测试过、上线使用过的国产数据库产品进行全面的解读,尽请期待!

 

参考资料

[1] MySQL官方手册(5.7,8.0)

[2] MySQL运维内参

 

 

你可能感兴趣的:(MySQL复制一致性问题探索(二)-MGR)