共计 5162 个字符,预计需要花费 13 分钟才能阅读完成。
01 多主模式
在多主模式下(group_replication_single_primary_mode = OFF),所有成员不会辨别 primary 和 standby 角色。退出该组时,与其余组成员兼容的任何成员都被设置为读写模式,并且能够解决写事务,即便它们是并发执行的。
如果组复制中的某个成员进行承受写事务,例如,在某个节点意外宕机的状况下,能够将与其连贯的客户端重定向或故障转移到处于读写模式的任何其余衰弱的成员。组复制自身不解决客户端故障转移,因而须要应用中间件框架(例如 MySQL Router 8.0,代理,连接器或应用程序自身)来实现。下图阐明了 MGR 集群的多主模式下故障转移的实现:
组复制在集群内保障了零碎的最终一致性。一旦入栈流量缩小,所有组成员将具备雷同的数据内容。当流量在集群外部下发时,事务能够在某些成员之间先进行长久化,特地是如果某些成员的写入吞吐量小于其余成员的状况下,则可能导致性能差的节点上读取到旧数据。在多主模式下,写入速度较慢的成员还可能积压过多的事务,从而导致更大的抵触和认证失败危险。为了防止这些问题,能够针对不同的业务场景应用组复制自带的流控机制,以最大水平地缩小不同成员之间的事务差别。对于 MGR 的流控机制,咱们在前面进行具体探讨。
从 MySQL 8.0.14 开始,如果要为集群中的每个事务都领有一个事务一致性保障,则能够应用 group_replication_consistency 零碎变量来做到这一点。能够抉择适宜集群工作负载和数据读写优先级的设置,同时思考到进步一致性整个集群对性能的影响。还能够为单个会话设置该零碎变量,用来爱护特地是对并发敏感的事务。无关事务一致性的更多信息,咱们在前面的章节详细描述。
02 事务形容
当 MGR 集群是以多主的模式在线上运行时,集群通过以下两条准则对不同成员之间的事务进行严格的一致性检测,以保障这些事务能够在集群内提交胜利:
1. 如果在 SERIALIZABLE 隔离级别下执行事务,则在集群中同步数据时,该事务将提交失败。
2. 如果事务是针对具备具备级联束缚的外键的表执行的,则在集群中同步数据时,该事务将提交失败。
group_replication_enforce_update_everywhere_checks 零碎变量管制上述行为。在多主模式下,通常应将零碎变量设置为 ON,然而能够抉择将零碎变量设置为 OFF 来禁用查看。在单主模式下部署时,必须将零碎变量设置为 OFF。
03 在多主模式的复制拓补中,执行 DDL 须要分外小心
MySQL 8.0 引入了对原子数据定义语言(DDL)语句的反对,其中残缺的 DDL 语句作为单个原子事务被提交或回滚。然而,DDL 语句隐式完结以后会话中处于活动状态的事务,就如同在执行该语句之前执行了 COMMIT 一样。这意味着 DDL 语句不能在另一个事务中执行,例如在事务管制语句(START TRANSACTION … COMMIT)中执行,也不能与同一事务中的其余语句组合。
如果对同一对象进行更改(应用 DDL)并更改对象蕴含的数据(应用 DML),则须要通过同一个节点解决更改,而 DDL 操作尚未实现并在各处复制。否则,当操作中断或仅局部实现时,可能导致数据不统一。如果集群以单主服务器模式部署,则不会产生此问题,因为所有数据更改都是通过同一个节点(主节点)执行的。
04 版本兼容性
为了获得最佳的兼容性和性能,集群中的所有成员应运行雷同版本的 MySQL Server,因而应运行雷同版本的组复制。在多主模式下,这更为重要,因为所有成员通常都将以读写模式退出该集群。如果集群中蕴含运行多个 MySQL Server 版本的成员,则某些成员可能与其余成员不兼容,因为它们反对其余成员不具备的性能或短少其余成员具备的性能。为了避免这种状况,当新成员退出(包含以前已降级并重新启动的成员)时,该成员将对组的其余成员执行兼容性查看。
这些兼容性查看的后果在多主模式下尤其重要。如果新加入成员所运行的 MySQL Server 版本高于现有组成员所运行的最低版本,则它将退出该组,但放弃只读模式。(在以单主模式运行的集群中,无论如何,新增加的成员在任何状况下均默认为只读。)运行 MySQL 8.0.17 或更高版本的成员在查看其兼容性时会思考该发行版的补丁程序版本。运行 MySQL 8.0.16 或更低版本或 MySQL 5.7 的成员仅思考次要版本。
在具备应用不同 MySQL Server 版本的成员的多主模式下运行的集群中,组复制会主动治理运行在 MySQL 8.0.17 或更高版本的成员的读写状态和只读状态。如果成员来到集群,则运行以后最低版本的成员将主动设置为读写模式。当应用 group_replication_switch_to_multi_primary_mode 自定义函数时,将以单主模式运行的组更改为以多主模式运行时,组复制会主动将成员设置为正确的模式。如果新增成员运行的 MySQL 版本高于组中存在的最低版本的成员,则该成员将主动置于只读模式,而运行最低版本的成员将处于读写模式。
05 MGR 服务
5.1 成员资格:
复制组由一组 MySQL Server 形成。集群具备一个惟一的名称,名称模式为 UUID 字符串。集群内的成员是动静的,成员能够随时脱离集群,也能够随时退出集群。每当有 Server 退出或脱离集群时,集群的相干信息都会进行主动调整。
如果一个 Server 退出了集群,则它会从集群的现有成员中主动获取本身缺失的数据状态以便和集群保持数据同步。如果一个成员脱离了集群,其余的成员会发现该成员脱离了集群,并主动重新配置集群。
组复制定义了集群内哪些成员在线且是沉闷成员。在线成员列表被称为组视图。集群中的每个成员都具备一个统一的视图,即示意在给定的时刻集群中哪些成员是沉闷成员。
组成员不仅在事务提交时必须达成统一,对于组视图的变更也必须达成统一。如果现有成员批准新的 Server 退出集群,则集群将被重新配置,以便将新节点集成到集群中,这将触发组视图的变更。如果组成员脱离集群,该集群将动静地重新配置,并触发组视图的变更。
在成员被迫脱离集群的状况下,它首先启动动静组重新配置,在此期间,所有组成员必须就新的组视图达成统一。然而,如果某个组成员是非自愿地脱离了集群,例如:因为意外宕机了或网络连接中断了,那么脱离集群的成员就不能启动动静重新配置。在这种状况下,组复制的故障检测机制会在短时间内辨认出该成员曾经脱离了集群,并倡议将已脱离组成员排除在外并进行动静重新配置组。重新配置组须要失去组中大多数组成员的批准。然而,如果此时集群内不能达成统一,例如:因为集群内沉闷节点数量少于节点总数量的半数时,零碎就不能动静重新配置集群,这种状况下集群会阻塞写访问以防止出现脑裂的状况。直到人工染指解决。
在故障检测机制检测到其故障之前,或在重新配置集群以删除该故障成员之前,容许组成员短暂离线,而后尝试重新加入集群。在这种状况下,重新加入的成员可能会失落它以前的事务数据,如果此时其余成员向它发送了蕴含该成员解体前的状态的音讯,则这就可能会导致一些问题(例如:可能导致数据不统一。)
为了解决这个问题,从 MySQL 5.7.22 及其之后的版本中,当 Server 退出一个集群时,会被赋予一个惟一的标识符。这使组复制可能察觉到同一 Server 的新化身(尽管具备雷同的地址,但不同的化身具备不同的标识符)试图退出组时,而其旧化身依然会作为成员列出。在通过重新配置组并删除旧的化身之前,将阻止新的化身退出组。如果通过零碎变量 group_replication_member_expel_timeout 的设置减少了疑似故障的成员在被驱赶出集群之前容许返回集群的等待时间,则只有疑似故障的成员不是真的故障了,那么被狐疑的那个成员在这个等待时间内就能够尝试重新加入集群。如果在被狐疑出故障的成员上执行了重启组复制,则该成员将成为新的化身,在狐疑超时之前(狐疑期工夫内)不能重新加入组。
5.2 故障检测:
组复制反对一种故障检测机制,该机制可能发现和列出哪些组成员是静默的,并假设静默的组成员曾经挂机。总体上讲,故障检测器是一种分布式服务,它提供对于哪些组成员可能死机的信息。当组成员静默时就会引发狐疑。当组成员 A 在给定的时间段内没有接管来自组成员 B 的音讯时,将产生音讯超时并引发狐疑。稍后,如果组内其余所有的成员通过协商之后,都批准对该成员的狐疑可能是实在的(少数节点断定的后果),则集群就会断定被狐疑的成员的确产生了故障。这意味着组中其余成员可能通过采取协调一致的决策来将故障成员驱赶出组(被断定为产生故障的成员)。
如果某个组成员与组中的其余成员产生了网络隔离,那么它会狐疑集群中其余所有成员都产生故障了。因为无奈与组内的其余成员进行协商(因为仲裁成员数有余),它的狐疑有效。此时,它也无奈执行任何本地事务(只读事务能够执行)。
5.3 容错性:
组复制建设在 Paxos 分布式算法的实现之上,以提供组成员之间的分布式协调。因而,它须要大多数组成员处于沉闷状态能力达到仲裁成员数,才可能做出决策。该要求会间接影响到零碎在不影响本身和整体可用性的状况下可能容忍产生故障的成员数量。能够容忍产生故障的成员数量(假如为 f 个)和要求组内总成员数量(假如为 n 个)之间的关系为:n = 2 x f + 1。
如果要容忍至多一个组成员产生故障,那么,组内的总成员数量至多须要 3 个。因而,当一个组成员产生故障时,依然有 2 个组成员是沉闷成员,即沉闷成员占多数(三分之二),此时,集群内可通过仲裁机制主动驱赶故障成员并容许零碎持续对外提供服务。然而,如果第二个组成员再产生故障(非被迫脱离组),则该集群(剩下一个成员)会产生阻塞,因为短少少数成员来做出正当的决策,所以无奈主动复原到能对外提供服务的状态,此时须要人工染指解决。
通常,基于性能和保护老本的思考,组内的成员总数量不倡议超过 7 个,最大只能 9 个。
5.4 可察看性:
尽管 MGR 插件内置了很多自动化性能。但有时可能须要理解幕后产生了什么。如果有须要,能够通过 performance_schema 下的表查问集群的整个状态(包含视图、抵触统计信息和服务状态等)。复制协定的分布式个性、以及组成员在事务和元数据上的一致性,要求组内的一些元数据和状态信息在组内所有成员间互相同步,这就使得检查组的状态等信息变得更加简略。你只须要连贯到集群内的任意一个成员中,并通过 performance_schema 下的相干复制状态信息表执行 select 语句进行查问,就能够获取到组相干的本地和全局信息。无关更多信息,咱们放在 MGR 状态监控中会具体探讨。
06 MGR 插件架构
MGR 的总体架构图如下:
MGR 插件蕴含一组用于捕捉,利用和生命循环的 API,这些 API 管制着 MGR 插件如何与 MySQL Server 交互。这些接口是搁置在事务执行管道中的一些钩子(它们将 MySQL Server 的外围与 MGR 插件隔离开来),逻辑上将 MySQL Server 内核与 MGR 插件隔离开来。其中有一些接口提供把通信信息从 Server 发送给 MGR 插件(例如:Server 启动、复原、承受连贯以及 Server 行将提交事务的事件告诉),有一些接口提供把通信信息从 MGR 插件发送给 MySQL Server(例如:MGR 插件命令 MySQL Server 提交、终止一个正在执行的事务,或者让该事务写入 relay log 中排队等待解决)。
在这些 API 的下一层,是一组组件(capture、applier、Recovery),组复制中的三个外围模块,当下层 API 产生调用,将依据调用类型路由到上面这三个模块执行相应的逻辑:
capture 组件负责跟踪与正在执行的事务相干的上下文信息。
applier 组件负责在数据库上利用近程事务,其实就是读取 relay log 中数据进行回放。
Recovery 组件治理数据库节点的分布式复原相干的工作,以及负责在一个新的 Server 退出集群时抉择一个疏导节点,协调新退出节点的数据追赶的更新步骤(包含相干的数据回追,失败解决等),以及对抉择疏导节点失败之后做出一些响应。简而言之就是治理集群成员的 recovery。
持续沿着堆栈向下,复制协定模块蕴含复制协定中的一些特定逻辑。例如:解决冲突检测,接管和流传事务到集群中。
MGR 插件体系结构的最初两层是组通信零碎 (GCS) API 和基于 paxos 的组通信引擎(XCom) 的实现。GCS API 是一个高级 API,它形象了构建复制状态机所需的属性,具体属性咱们在前文曾经形容过了。因而,它将音讯层的实现与插件的其余下层组件解耦。组通信引擎解决与复制组成员之间的通信,次要提供基于 Paxos 协定的变体实现数据一致性的外围性能。