注:本文翻译自https://dev.mysql.com/doc/refman/8.0/en/group-replication.html
背景
创建容错系统的最常见方法是使组件冗余,换句话说,可以删除组件,而系统应继续按预期运行。这就产生了一系列挑战,将这类系统的复杂性提升到了一个完全不同的水平。具体来说,复制数据库必须处理这样一个事实,即它们需要维护和管理多台服务器,而不仅仅是一台服务器。此外,当服务器一起协作创建组时,必须处理其他几个经典的分布式系统问题,例如网络分区或分裂大脑场景。
因此,最终的挑战是将数据库和数据复制的逻辑与以一致和简单的方式协调多个服务器的逻辑融合在一起。换句话说,要让多个服务器就系统的状态和系统所经历的每次更改的数据达成一致。这可以概括为让服务器在每个数据库状态转换上达成一致,以便它们都作为一个数据库前进,或者它们最终收敛到相同的状态。这意味着它们需要作为(分布式)状态机进行操作。
MySQL组复制提供分布式状态机复制,在服务器之间具有很强的协调性。当服务器属于同一组时,它们会自动进行协调。该组可以在具有自动主选举的单主模式下运行,其中一次只有一个服务器接受更新。或者,对于更高级的用户,可以将组部署在多主模式中,其中所有服务器都可以接受更新,即使它们是并发发布的。这种能力的代价是应用程序必须绕过这种部署所施加的限制。
有一个内置的组成员服务,它可以保持组视图的一致性,并在任何给定的时间点对所有服务器可用。服务器可以离开或加入组,视图也会相应地更新。有时,服务器可能会意外地离开组,在这种情况下,故障检测机制会检测到这种情况,并通知组视图已更改。这都是自动的。
为了提交事务,组中的大多数成员必须就给定事务在全局事务序列中的顺序达成一致。决定提交或中止事务是由每个服务器单独完成的,但所有服务器都做出相同的决定。如果存在网络分区,导致成员无法达成协议的分裂,则系统不会继续进行,直到此问题得到解决。因此,也有一个内置的,自动的,分裂的大脑保护机制。
所有这些都由提供的组通信系统(GCS)协议提供支持。它们提供了故障检测机制、组成员服务以及安全且完全有序的消息传递。所有这些属性对于创建一个确保数据在服务器组之间一致复制的系统至关重要。该技术的核心是Paxos算法的实现。它充当群组通信引擎。
传统复制技术
传统的MySQL Replication提供了一种简单的从源到副本的复制方法。源是主要的,有一个或多个副本,它们是次要的。源应用事务,提交它们,然后(因此是异步的)将它们发送到副本,以便重新执行(在基于语句的复制中)或应用(在基于行的复制中)。它是一个无共享的系统,默认情况下,所有服务器都有数据的完整副本。
还有一种半同步复制,它在协议中添加了一个同步步骤。这意味着主服务器在应用时等待辅助服务器确认它已接收到事务。只有这样,主服务器才能恢复提交操作。
在这两张图中,有一个经典的异步MySQL复制协议的示意图(以及它的半同步变体)。不同实例之间的箭头表示服务器之间交换的消息或服务器与客户端应用程序之间交换的消息。
组复制
组复制是一种可用于实现容错系统的技术。复制组是一组服务器,每个服务器都有自己的完整数据副本(无共享复制方案),并通过消息传递相互交互。通信层提供了一组保证,例如原子消息和总订单消息传递。这些都是非常强大的属性,可以转化为非常有用的抽象,可以用来构建更高级的数据库复制解决方案。
MySQL组复制建立在这样的属性和抽象之上,并实现了一个多源更新无处不在的复制协议。复制组由多个服务器组成,组中的每个服务器可以在任何时候独立执行事务。然而,所有读写事务只有在被组批准后才会提交。换句话说,对于任何读写事务,组需要决定是否提交,因此提交操作不是来自原始服务器的单方面决定。只读事务不需要组内的协调,可以立即提交。
当读写事务准备在原始服务器上提交时,服务器会自动广播写值(已更改的行)和相应的写集(已更新行的唯一标识符)。因为事务是通过原子广播发送的,所以要么组中的所有服务器都接收到事务,要么没有服务器接收到事务。如果他们收到它,那么他们都以与之前发送的其他交易相同的顺序收到它。因此,所有服务器都以相同的顺序接收相同的事务集,并为这些事务建立一个全局总顺序。
但是,在不同服务器上并发执行的事务之间可能存在冲突。这种冲突是通过检查和比较两个不同并发事务的写集来检测的,这个过程称为认证。在认证期间,冲突检测是在行级别执行的:如果在不同服务器上执行的两个并发事务更新了同一行,那么就存在冲突。冲突解决过程声明,首先排序的事务在所有服务器上提交,然后排序的事务终止,因此在原始服务器上回滚,并由组中的其他服务器删除。例如,如果t1和t2在不同的站点并发执行,都更改同一行,并且t2在t1之前排序,则t2在冲突中获胜,t1被回滚。这实际上是一个分布式的先提交获胜规则。请注意,如果两个事务经常发生冲突,那么最好在同一台服务器上启动它们,这样它们就有机会在本地锁管理器上同步,而不是由于认证而回滚。
为了应用和外部化经过认证的事务,如果不破坏一致性和有效性,Group Replication允许服务器偏离商定的事务顺序。Group Replication是一个最终一致性系统,这意味着一旦传入流量减慢或停止,所有组成员都具有相同的数据内容。当流量流动时,事务可以以稍微不同的顺序外部化,或者在其他成员之前外部化一些成员。例如,在多主模式下,本地事务可能会在认证之后立即外部化,尽管还没有应用全局顺序中较早的远程事务。当认证过程确定事务之间不存在冲突时,这是允许的。在单主模式下,在主服务器上,并发的、无冲突的本地事务可能以与Group Replication商定的全局顺序不同的顺序提交和外部化。在不接受客户端写的辅助服务器上,事务总是按照约定的顺序提交和外部化。
下图描述了MySQL组复制协议,并将其与MySQL复制(甚至MySQL半同步复制)进行比较,您可以看到一些差异。为了清晰起见,在这幅图中遗漏了一些潜在的共识和与Paxos相关的信息。
多主模式和单主模式
组复制可以在单主模式或多主模式下运行。组的模式是组范围的配置设置,由系统变量group_replication_single_primary_mode指定,该变量在所有成员上必须相同。ON表示默认模式为单主模式,OFF表示多主模式。不可能将组的成员部署在不同的模式中,例如,一个成员配置为多主模式,而另一个成员配置为单主模式。
当“组复制”正在运行时,不能手动修改“group_replication_single_primary_mode”的值。从MySQL 8.0.13开始,您可以使用group_replication_switch_to_single_primary_mode()和group_replication_switch_to_multi_primary_mode()函数在组复制仍在运行时将组从一种模式移动到另一种模式。这些功能管理更改组模式的过程,并确保数据的安全性和一致性。在早期版本中,要更改组的模式,必须停止group Replication并在所有成员上更改group_replication_single_primary_mode的值。然后执行组的完全重新启动(由服务器启动,其中group_replication_bootstrap_group=ON),以实现对新操作配置的更改。不需要重新启动服务器。
无论采用何种部署模式,Group Replication都不处理客户端故障转移。这必须由中间件框架(如MySQL Router 8.0)、代理、连接器或应用程序本身来处理。
组复制插件架构
MySQL Group Replication是一个MySQL插件,它建立在现有的MySQL复制基础设施上,利用了二进制日志、基于行的日志记录和全局事务标识符等特性。它集成了当前的MySQL框架,如性能模式或插件和服务基础设施。下图是一个描述MySQL组复制整体架构的框图。
MySQL Group Replication插件包括一组用于捕获、应用和生命周期的api,这些api控制插件如何与MySQL服务器交互。有一些接口可以使信息流从服务器流向插件,反之亦然。这些接口将MySQL Server核心与Group Replication插件隔离开来,并且大多数是放置在事务执行管道中的钩子。在一个方向上,从服务器到插件,有事件通知,例如服务器启动、服务器恢复、服务器准备接受连接以及服务器即将提交事务。在另一个方向上,插件指示服务器执行诸如提交或中止正在进行的事务,或在中继日志中排队事务等操作。
Group Replication插件体系结构的下一层是一组组件,当通知路由到它们时,它们会做出反应。捕获组件负责跟踪与正在执行的事务相关的上下文。应用程序组件负责在数据库上执行远程事务。恢复组件管理分布式恢复,并负责通过选择提供者、管理赶上过程和对提供者失败作出反应,使加入组的服务器保持最新状态。
沿着堆栈向下,复制协议模块包含复制协议的特定逻辑。它处理冲突检测,接收事务并将其传播到组。
组复制插件架构的最后两层是组通信系统(GCS) API和基于paxos的组通信引擎(XCom)的实现。GCS API是一个高级API,它抽象了构建复制状态机所需的属性。因此,它将消息传递层的实现与插件的其余上层解耦。组通信引擎处理与复制组成员的通信。