MySQL组复制详解(一)——基本原理
一、什么是组复制
MySQL Group Replication(MGR)是MySQL 5.7.17版本引入的一个服务器插件,可用于创建高可用、可扩展、容错的复制拓扑结构。组复制可以在单主模式下操作,其中只有一个服务器接受更新,这个单主是系统自动选举出来的。对于高级用户,也可以部署为多主模式,其中所有服务器都可以接受更新。内置的组成员服务可以在任何给定的时间点保持组的视图一致并可供所有服务器使用。当服务器加入或离开组时,视图也会相应更新。当服务器宕机,故障检测机制会检测到此情况并通知组其视图已更改。这些都是自动进行的。
MGR对属于同一组的服务器自动进行协调。对于要提交的事务,组成员必须就全局事务序列中给定事务的顺序达成一致。提交或回滚事务由每个服务器单独完成,但所有服务器都必须做出相同的决定。如果存在网络分区,导致成员无法达成事先定义的分割策略,则在解决此问题之前系统不会继续进行,这是一种内置的自动裂脑保护机制。MGR由组通信系统(Group Communication System,GCS)协议支持。该系统提供故障检测机制、组成员服务以及安全且有序的消息传递。所有这些属性都是创建系统的关键,可确保在服务器组中一致地复制数据。该技术的核心是Paxos算法的实现,它充当组通信引擎。
二、组复制的应用场景
组复制可用来创建具有冗余的容错系统。即使某些服务器发生故障,只要它不是全部或大多数,系统仍然可用。根据失败的服务器数量,可能会降低性能或可伸缩性,但它仍然可用。组成员服务跟踪服务器故障,该服务依赖于分布式故障检测器,能够在任何服务器脱离组时发出信号,无论是意外停止还是主动停止。分布式恢复过程确保当服务器加入组时能自动更新。单个服务器发生故障时不会停止服务,也无需服务器故障转移。总之,MGR保证数据库服务持续可用。
以下是组复制的典型使用场景。
- 弹性复制:服务器的数量能够动态增加或减少,并且尽可能减小副作用,例如云数据库服务。
- 高可用分片:分片是实现写扩展的流行方法。使用MGR实现高可用分片,其中每个分片映射到复制组。
- 主从复制的替代方案:在某些情况下,使用单个主服务器会使其成为热点,写入整个组会更具可扩展性。
三、组复制插件架构
MGR插件包含一组捕获、应用和生命周期API,用于控制插件与MySQL服务器的交互方式。这些接口将MySQL服务器核心与MGR插件隔离。服务器向插件通知启动、恢复、准备接收连接、即将提交事务等消息。插件指示服务器执行诸如提交事务、中止正在进行的事务、事务在中继日志中排队等动作。
组复制插件体系结构的下一层是一组组件。捕获组件负责跟踪与正在执行的事务相关的上下文。应用组件负责在数据库上执行远程事务。恢复组件管理分布式恢复,负责选择捐赠者,对故障做出反应,执行追赶程序,使加入该组的服务器获得更新。
堆栈下一层的复制协议模块包含复制协议的特定逻辑。它处理冲突检测,接收事务并将其传播到组。
组复制插件体系结构的最后两层是组通信系统(GCS)API,以及基于Paxos的组通信引擎(XCom)的实现。GCS API将消息传递层的实现与插件上层分离,组通信引擎处理与复制组成员的通信。
四、组复制实现原理
组由多个服务器构成,通过传递消息进行交互,通信层保证原子消息传递。MGR构建于此通信层抽象之上,并实现了多主更新复制协议。组中的每个服务器独立地执行事务,但是所有读写事务只有在得到组的批准后才会提交。只读事务在组内不需要协调,因此立即提交。对于任何读写事务,当事务准备好在始发服务器处提交时,服务器以原子方式广播写入值(更改的行)和对应的写入集(更新的行的唯一标识符),然后将该事务加入全局事务列表。最终所有服务器都以相同的顺序接收并应用相同的事务集,所以它们在组内保持一致。
不同服务器上并发执行的事务之间可能存在冲突。MGR在certify过程中检查并发事务的写集来检测这种冲突。如果在不同服务器上执行的两个并发事务更新同一行,则存在冲突。解决方案是先到事务提交,后到事务回滚,即按顺序第一个事务在所有服务器提交,而第二个事务在在原始服务器上回滚并在组中的其它服务器中删除。这实际上体现的是多主分布式事务的首个提交获胜原则。
五、组复制的工作流程
MGR中的一组服务器构成一个复制组,组名形式为UUID。组是动态的,服务器可以离开(主动或被动)并随时加入组。服务器加入或离开时,组会自行调整。如果服务器加入组,组会通过从现有服务器获取状态自动更新新加入的服务器。状态通过MySQL异步复制进行传输。如果服务器离开该组,其余服务器会知道它已离开并自动重新配置该组。
1、分布式恢复原理
组复制分布式恢复可以概括为服务器从组中获得丢失事务的过程,以便它可以加入具有已处理相同事务集成员的组。在分布式恢复期间,加入组的服务器会缓冲其正在接收的,组中所需的事务和成员事件。一旦加入该组的服务器收到了该组的所有事务,它就会应用在恢复过程中缓冲的事务。此过程结束时,服务器随之作为在线成员加入组。分布式恢复分为两个阶段。
1)第一阶段:加入该组的服务器选择该组上的一个在线服务器作为其缺失状态的捐赠者。捐赠者负责为新服务器提供加入该组的所有数据,直到它加入该组为止。这是通过在捐赠者和加入该组的服务器之间建立的标准异步复制通道来实现的。复制通道是MySQL 5.7 中提出的概念。简单讲一个复制通道表示从主库到从库的一条复制路径,在多源复制中主到从可以存在多条复制通道。通过此复制通道复制捐赠者的二进制日志,直到加入该组的服务器成为该组的一部分,并发生视图更改时。加入该组的服务器在收到捐赠者的二进制日志时应用它们。复制二进制日志时,加入该组的服务器还会缓存在组内交换的每个事务。也就是说,它监听在加入该组之后发生的事务,同时应用来自捐赠者的数据。
2)第二阶段:追赶。在此阶段,加入组的服务器继续执行高速缓存的事务。排队等待执行的事务数最终达到零时,该成员将在线声明。当加入组的服务器从捐赠者获取二进制日志时,恢复过程可以承受捐赠者故障。在这种情况下,捐赠者在第一阶段期间失败时,加入该组的服务器将故障转移到新的捐赠者并从新捐赠者恢复。加入该组的服务器将关闭与失败的捐赠者的连接,并打开与新捐赠者的连接,这些都是自动进行的。
2、二进制日志视图
为了使加入组的服务器与捐赠者同步到特定时间点,加入组和捐赠者的服务器利用MySQL全局事务标识符(GTID)机制。但GTID仅提供了一种方法来发现加入该组的服务器缺少哪些事务,不会传达认证信息。这是二进制日志视图标记的工作,它标记二进制日志流中的视图更改,还包含其它元数据信息,如认证相关数据。
视图对应于主动参与当前配置的一组成员,在特定时间点,这些组成员在系统中是正确的和在线的。视图更改发生在组配置修改(例如成员加入或离开)时。任何组成员身份更改都会导致在同一逻辑时间点向所有成员传达视图更改。视图标识符唯一标识视图。只要视图发生更改,就会生成一个视图标识符。在通信层,视图更改及其关联的视图ID是成员加入之前和之后数据变化的边界。此概念通过新的二进制日志事件实现:“视图更改日志事件”。因此视图ID也成为在组成员资格发生变化之前和之后传输的事务的标记。视图标识符本身由两部分构成:随机部分和单调递增整数部分。第一部分在创建组时生成,并且在组中至少有一个成员时保持不变。每次视图更改发生时,第二部分都会递增。随机部分识别组的开始,增量部分标识组的改变。
3、分布式恢复过程
1)开始:稳定组
所有服务器都在线并处理来自组的传入事务。一些服务器复制的事务可能稍微落后,但最终它们会相同。此时该组充当一个分布式数据库副本。
2)视图更改:加入一个组成员
每当新成员加入组并因此执行视图更改时,每个联机服务器都会把视图更改日志事件排入队列以备执行。在视图更改之前,服务器上可能有一些属于旧视图的事务排队进行应用,将视图更改事件排在它们之后可确保正确标记何时发生了视图更改。同时,加入该组的服务器通过视图的在线服务器列表中选择捐赠者。如图所示,成员加入时生成视图4,在线成员将此视图更改事件写入二进制日志。
3)状态转移:追赶
一旦加入该组的服务器选择该组中的某服务器作为捐赠者,则在两者之间建立新的异步复制连接并且开始状态转移(第一阶段)。这种与捐赠者的交互一直持续到服务器加入组的应用程序线程,该线程处理服务器进入组时所触发的视图更改日志事件。加入该组的服务器从捐赠者复制,直到它到达与视图改变相匹配的视图标识符,如图所示。
加入该组的服务器知道它应该在哪个视图标识符停止复制。由于视图标识符在相同的逻辑时间被发送到组中的所有成员,避免了复杂的GTID集合计算,因为视图ID清楚地标记了属于每个组视图的数据。
加入该组的服务器正在从捐赠者复制时,它也会缓存来自该组的传入事务。最后它停止从捐赠者复制并切换到应用缓存的那些事务,如图所示。
4)完成:赶上
当加入组的服务器识别出具有预期视图标识符的视图更改日志事件时,终止与捐赠者的连接并开始应用缓存的事务。视图更改日志事件除了在二进制日志中充当分隔标记,还扮演另一个角色。当新服务器进入组时,它传达所有服务器感知的认证信息,即最后的视图改变。如果没有视图更改事件,加入该组的服务器将没有必要的信息对后续事务进行冲突检测。
追赶的持续时间(第二阶段)是不确定的,它取决于负载和进入组的事务的多少。此过程完全联机,加入组的服务器在追赶时不会阻止组中的任何其它服务器。当进行到第二阶段时,加入该组的服务器的事务可能落后,落后的多少取决于负载。当加入组的服务器达到零排队事务并且其存储的数据等于其它成员时,其公共状态将更改为联机,如图所示。
4、分布式恢复的使用建议和限制
分布式恢复基于传统的异步复制,如果加入组的服务器没有数据或者只有非常旧的备份数据,恢复过程可能很慢。这意味着要在第一阶段传输大量数据,新增服务器可能需要很长时间才能恢复。因此建议在将服务器添加到组之前,应该为其配置已经在组中的服务器的相当近的快照。这最小化了第一阶段的所需时间并减少了对捐赠服务器的影响,因为它只需保传输较少的二进制日志。