绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
17.9 组复制技术细节
2020-05-11 11:20:24

参考官方文档:

dev.mysql.com/doc/refma


17.9.1 组复制插件架构


MySQL Group Replication是一个MySQL插件,它基于现有的MySQL复制基础架构,利用二进制日志,基于行的日志记录和全局事务标识符等功能。 它与当前的MySQL框架集成,例如性能模式或插件和服务基础结构。 下图显示了描述MySQL Group Replication整体架构图。





MySQL Group Replication插件包含一组用于捕获,应用和生命周期的API,用于控制插件与MySQL Server的交互方式。 有一些接口可以使信息从服务器流向插件,反之亦然。 这些接口将MySQL Server核心与Group Replication插件隔离开来,并且主要是放置在事务执行管道中的钩子。 在一个方向上,从服务器到插件,有一些事件的通知,例如服务器启动,服务器恢复,服务器准备接受连接,以及服务器即将提交事务。 在另一个方向上,插件指示服务器执行诸如提交或中止正在进行的事务或在中继日志中排队事务之类的操作。


组复制插件体系结构的下一层是一组组件,它们在被路由到它们时作出反应。 捕获组件负责跟踪与正在执行的事务相关的上下文。 应用程序组件负责在数据库上执行远程事务。 恢复组件管理分布式恢复,并负责选择供体,并对供体故障作出反应,使加入该组的服务器到新。


继续向下stack,复制协议模块包含复制协议的特定逻辑。 它处理冲突检测,并接收事务并将事务传播到组。


组复制插件体系结构的后两层是组通信系统(GCS)API,以及基于Paxos的组通信引擎的实现。 GCS API是一个API,它抽象了构建复制状态机所需的属性(请参见第17.1节“组复制背景”)。 因此,它将消息传递层的实现与插件的其余上层分离。 组通信引擎处理与复制组成员的通信。



17.9.2 组


在MySQL Group Replication中,一组服务器构成一个复制组。 组具有名称,其形式为UUID。 该组是动态的,服务器可以离开(自愿或非自愿)并随时加入。 服务器加入或离开时,该组会自行调整。


如果服务器加入组,它会通过从现有服务器获取丢失状态自动使其自身达到新。 此状态通过异步MySQL复制进行传输。 如果服务器离开该组,例如它被取下进行维护,则其余服务器会注意到它已经离开并自动重新配置该组。 第17.1.3.2节“组成员资格”中描述的组成员服务支持所有这些。


17.9.3 数据操作语句


由于任何特定数据集都没有主服务器(主服务器),因此允许组中的每个服务器随时执行事务,甚至是更改状态的事务(RW事务)。


任何服务器都可以在没有任何先验协调的情况下执行事务。 但是,在提交时,它与组中的其他服务器协调,以便就该事务的命运做出决定。 这种协调有两个目的:(i)检查交易是否应该提交; (ii)并传播更改,以便其他服务器也可以应用该事务。


当事务通过原子广播发送时,组中的所有服务器都接收事务,或者不接收任何事务。 如果他们收到它,那么他们都会按照之前发送的其他事务的相同顺序收到它。 通过检查和比较写入的事务集来执行冲突检测。 因此,它们在行级被检测。 冲突解决遵循个提交者获胜规则。 如果t1和t2在不同的站点同时执行,因为t2在t1之前被排序,并且两者都改变了同一行,那么t2赢得冲突并且t1中止。 换句话说,t1试图改变已被t2渲染的数据。


注意

如果两个事务经常发生冲突,那么在同一台服务器上启动它们是一个好习惯。 那么,他们有机会在本地锁管理器上进行同步,而不是之后在复制协议中中止。


17.9.4 数据定义语句


在组复制拓扑中,在执行通常称为数据定义语言(DDL)的数据定义语句时需要小心。 鉴于MySQL不支持原子或事务DDL,人不能乐观地执行DDL语句,并按需要回滚。 因此,缺乏原子性并不直接适合组复制所基于的乐观复制范例。


因此,在复制数据定义语句时需要更加小心。在方案操作尚未完成并在任何位置进行复制时, 方案变更和包含对象的数据更改需要通过同一服务器处理。 如果不这样做可能会导致数据不一致。


注意:

如果组以单主模式部署,则这不是问题,因为所有更改都是通过同一服务器(主服务器)执行的。


警告:

MySQL DDL执行不是原子的或事务性的。 服务器首先执行并提交而不保护组协议。 因此,在DDL正在执行并且尚未在任何地方进行复制时,您必须通过同一服务器为同一对象路由DDL和DML


17.9.5 分布式恢复


17.9.5.1 分布式恢复基础


组复制分布式恢复可以概括为服务器从组中丢失事务的过程,以便它可以加入已处理与其他组成员相同的事务集的组。 在分布式恢复期间,加入组的服务器将缓冲在加入组的服务器正在接收组中所需的事务时发生的任何事务和成员事件。 一旦加入该组的服务器收到了该组的所有事务,它就会应用在恢复过程中缓冲的事务。 在此过程结束时,服务器然后作为在线成员加入组。


阶段1


在阶段,加入该组的服务器选择该组上的一个在线服务器作为其缺失状态的供体。 供体负责为服务器提供加入该组的所有数据,直到它加入该组为止。 这是通过依赖于在供体和加入该组的服务器之间建立的标准异步复制通道来实现的,请参见第16.2.3节“复制通道”。 通过此复制通道,将复制供体的二进制日志,直到当加入该组的服务器成为该组的一部分时发生视图更改。 加入该组的服务器应用从供体接受的二进制日志。


在复制二进制日志时,加入该组的服务器也会缓存组内交换的每个事务。 换句话说,它正在侦听在加入该组之后发生的事务,同时它正在应用来自供体的缺失状态。 当阶段结束并且关闭供体的复制通道时,加入该组的服务器然后开始第二阶段:追赶。


阶段2


在此阶段,加入组的服务器继续执行缓存的事务。 排队等待执行的事务数终达到零时,该成员将被声明为在线。


弹性


当加入组的服务器从中获取二进制日志时,恢复过程可以承受供体故障。 在这种情况下,每当供体在阶段1期间失败时,加入该组的服务器将故障转移到新的供体并从该供体恢复。 当发生这种情况时,加入该组的服务器将显式关闭与该组故障服务器的连接,并打开与新供体的连接。 这会自动发生


17.9.5.2从时间点恢复


为了使加入组的服务器与供体同步到特定时间点,加入组的服务器和供体的服务器利用MySQL全局事务标识符(GTID)机制。 请参见第16.1.3节“使用全局事务标识符进行复制”。 但是,GTIDS仅提供了一种方法来实现加入该组的服务器缺少哪些事务,它们无助于标记加入该组的服务器必须赶上的特定时间点,也无助于传达认证信息。 这是二进制日志视图标记的工作,它标记二进制日志流中的视图更改,还包含其他元数据信息,为加入组服务器配置缺少认证相关的数据。


视图和视图变更


view对应于主动参与当前配置的一组成员,换句话说,在特定时间点。 它们在系统中是正确的和在线的。


当对组配置进行修改(例如成员加入或离开)时,会发生视图更改。 任何组成员身份更改都会导致在同一逻辑时间点向所有成员传达单独的视图更改。


视图标识符标识视图。 只要视图发生更改,就会生成它


在组通信层,视图更改及其关联的视图ID是成员加入之前和之后交换的数据之间的边界。 此概念通过新的二进制日志事件实现:“视图更改日志事件”。 因此,视图id也成为在组成员资格发生变化之前和之后发送的事务的标记。


视图标识符本身由两部分构成:(i)随机生成的数和(ii)单调递增的整数。 部分是在创建组时生成的,并且在组中至少有一个成员时保持不变。 每次视图更改发生时,第二部分都会递增。


型成视图id的这种异构对的原因是需要在成员加入或离开时明确地标记组更改,而且每当所有成员离开组时都没有信息,并且没有关于组所在视图的信息。事实上, 单独使用单调增加标识符可能导致在完全组关闭后重用相同的id,从而破坏恢复所依赖的二进制日志数据标记的性。


17.9.5.3 视图变更


本节介绍控制如何将视图更改标识符合并到二进制日志事件并写入日志的过程。执行以下步骤:


开始:稳定的组


所有服务器都在线并处理来自组的传入事务。 一些服务器在复制的事务方面可能略微落后,但终它们会汇合。 该组充当一个分布式和被复制数据库。






视图变更:成员加入


每当新成员加入组并因此执行视图更改时,每个在线服务器都会对视图更改日志事件执行进行排队。 这是被排队的,因为在视图更改之前,可以在要应用的服务器上排队多个事务,因此,这些事务属于旧视图。 在它们之后对视图更改事件进行排队可以保证正确标记何时发生这种情况。


同时,加入该组的服务器通过视图抽象从成员服务所述的在线服务器列表中选择供体。 成员加入视图4,在线成员将查看更改事件写入二进制日志。




状态传输:赶上


一旦加入组的服务器选择了组中的哪个服务器作为供体,则在两者之间建立新的异步复制连接并且状态转移开始(阶段1)。 这种与供体的交互一直持续到服务器加入组的应用程序线程处理视图更改日志事件,该事件对应于加入组的服务器进入组时触发的视图更改。 换句话说,加入该组的服务器从供体复制,直到它的标记到达具有与其已经存在的视图标记相匹配的视图标识符为止。



由于视图标识符在相同的逻辑时间被发送到组中的所有成员,因此加入该组的服务器知道应该在哪个视图标识符停止复制。 这避免了复杂的GTID集计算,因为视图ID清楚地标记了属于每个组视图的数据。


当加入该组的服务器从供体复制时,它也缓存来自该组的传入事务。 终,它停止从供体复制并切换到应用缓存。




完成:追赶


当加入组的服务器识别出具有预期视图标识符的视图更改日志事件时,终止与供体的连接并开始应用缓存的事务。 需要了解的重点是终的恢复程序。 虽然它在二进制日志中充当标记,但是分隔视图更改,视图更改日志事件也扮演另一个角色。 当加入组的服务器进入组时,它传达所有服务器感知的认证信息,换言之,后一次视图改变。 没有它,加入该组的服务器将没有必要用来证明(检测冲突)后续事务的信息。


追赶的持续时间(阶段2)不是确定性的,因为它取决于工作量和进入集团的事务的速率。 此过程完全联机,加入组的服务器在捕获时不会阻止组中的任何其他服务器。 因此,当移动到阶段2时服务器加入该组的落后事务的数量,会根据工作量而变化并因此增加或减少。


当加入组的服务器达到零排队事务并且其存储的数据等于其他成员时,其公共状态将更改为online。




17.9.5.4 分布式恢复的使用建议和限制


分布式恢复确实有一些限制。 它基于经典的异步复制,因此如果根本没有配置过加入组的服务器或者配置了非常旧的备份映像,它可能会很慢。 这意味着如果要在第1阶段传输的数据太大,服务器可能需要很长时间才能恢复。 因此,建议在将服务器添加到组之前,应该为其配置已经在组中的服务器的相当近的快照。 这小化了阶段1的长度并减少了对供体服务器的影响,因为它只用保存和传输较少的二进制日志。


警告:

建议在将服务器添加到组之前配置服务器(初始化数据)。 这样,可以大限度地减少恢复步骤所花费的时间。



17.9.7 组复制性能


17.9.7.1 优化群组通信线程


组通信线程(GCT)在加载组复制插件时循环运行。 GCT从组和插件接收消息,处理与仲裁和故障检测相关的任务,发送一些保持活动消息,并且还处理from/to 服务器/组的传入和传出事务。 GCT等待队列中的传入消息。 当没有消息时,GCT会等待。 通过将等待实际进入睡眠状态之前的时间设置稍长一些(进行主动等待)被证明在某些情况下是有益的。 这是因为操作系统可以选择从处理器对GCT进行上下文切换。


要强制GCT执行主动等待,请使用group_replication_poll_spin_loops选项,此选项让GCT 在实际轮询队列以查找下一条消息之前 进行循环,与循环数无关,。


mysql> SET GLOBAL group_replication_poll_spin_loops= 10000;


17.9.7.2 消息压缩


当网络带宽成为瓶颈时,消息压缩可以在组通信级别提供高达30-40%的吞吐量提升。 这在大型服务器组的上下文负载中尤为重要。


组中N个参与者之间的互连的TCP对等性质使得发送者发送相同数量的数据N次。所以压缩能大幅度提升带宽性能。






压缩发生在组通信引擎级别,在数据传递给组通信线程之前,因此它发生在mysql用户会话线程的上下文中。事务负载可以在被发送到组之前被压缩并且在被接收时被解压缩。压缩是有条件的,取决于配置的阈值。默认情况下,启用压缩。


此外,不要求组中的所有服务器都启用了压缩以便能够一起工作。在收到消息后,成员检查消息信封以验证它是否被压缩。如果需要,则成员在将事务传递到上层之前解压缩事务。


使用的压缩算法是LZ4。默认情况下启用压缩,阈值为1000000字节。压缩阈值(以字节为单位)可以设置为大于默认值的值。在这种情况下,仅压缩具有大于阈值的有效负载的事务。以下是如何设置压缩阈值的示例。


STOP GROUP_REPLICATION;

SET GLOBAL group_replication_compression_threshold= 2097152; START GROUP_REPLICATION;


这将压缩阈值设置为2MB。 如果事务生成有效负载大于2MB的复制消息,例如大于2MB的二进制日志事务条目,则会对其进行压缩。 禁用压缩设置阈值为0。



17.9.7.3 流控制

组复制确保事务仅在组中的大多数成员收到事务后提交,并同意所有并发发送的事务之间的相对顺序。


如果对组的写入总数不超过组中任何成员的写入容量,则works是合适的。 如果确实如此,并且某些成员的写入吞吐量低于其他成员,特别是少于write成员,那些成员可能会开始落后于作者。


让一些成员落后于该组会带来一些问题后果,特别是对这些成员的读取可能会表现出非常落后的数据。 根据成员滞后的原因,组中的其他成员可能必须保存更多或更少的复制上下文,以便能够满足来自落后成员的潜在数据传输请求。


然而,在复制协议中存在一种机制,以避免在快速和慢速成员之间在应用的事务方面出现太远的距离。 这被称为流量控制机制。 它试图解决几个目标:


  • 保持成员足够接近,使成员之间的缓冲和再同步成为一个小问题;
  • 快速适应不同工作负载或组中更多writer的不断变化的条件;
  • 给每个成员公平分享可用的写入能力;
  • 不会因为了避免浪费资源而严格限制吞吐量。



考虑到组复制的设计,可以考虑两个工作队列来决定是否增加,(i)认证队列; (ii)和二进制日志应用程序队列。 只要其中一个队列的大小超过用户定义的阈值,就会触发限制机制。 仅配置:(i)是在人在者或应用者级别进行流量控制,还是两者都配置; (ii)每个队列的阈值是多少。


流量控制取决于两种基本机制:

  • 监控收集一些关于所有小组成员的吞吐量和队列大小的统计数据,以便对每个成员应该承受的大写入压力做出有根据的猜测;
  • 试图在任意时刻写出超出其公平份额限制的容量。


17.9.7.3.1 探测和统计信息


监视机制的工作原理是让每个成员部署一组探测器来收集有关其工作队列和吞吐量的信息。 然后,它会定期将该信息传播给该组,以便与其他成员共享该数据。


此类探针分散在整个插件堆栈中,允许形成指标,例如:


  • 验证者队列大小;
  • 复制应用者队列大小;
  • 经认证的事务总数;
  • 成员中被应用的远程事务总数;
  • 本地事务总数。


成员收到包含来自其他成员的统计信息的消息后,将计算有关在上一个监视期间认证,应用和本地执行的事务数量的其他指标。


监控数据定期与组中的其他人共享。 监视周期必须足够高,以允许其他成员决定当前的写入请求,但必须足够低,以至于它对组带宽的影响小。 信息每秒共享一次,这段时间足以解决这两个问题。



17.9.7.3.2组复制节流


根据在组中所有服务器上收集的度量标准,限制机制启动并决定是否限制成员能够执行/提交新事务的速率。


因此,从所有成员获取的指标是计算每个成员的基础容量:如果成员具有大型队列(用于认证或应用程序线程),则执行新事务的能力应接近经认证或应用于后的时间段。


组中所有成员的低容量决定了组的实际容量,而本地事务的数量决定了写入组的成员数量,因此,应该与这些成员共享可用容量。


这意味着每个成员都有一个基于可用容量的已建立的写入配额,换句话说,它可以安全地为下一个时期发布的一些事务。如果验证者或二进制日志应用程序的队列大小超过用户定义的阈值,则限制机制将强制执行writer-quota。


配额减少了上一期间延迟的事务数,以允许触发问题的队列减小其10%大小。为了在队列大小超过阈值时避免吞吐量的大幅跳跃,之后每个周期仅允许吞吐量增长10%。


当前的限制机制不会对低于配额的事务进行处罚,但会延迟完成那些超过配额的事务,直到监控期结束。因此,如果发出的写请求的配额非常小,则某些事务可能具有接近监视时段的延迟。

分享好友

分享这个小栈给你的朋友们,一起进步吧。

MySQL干货资料
创建时间:2020-05-06 14:18:32
每天都有干货输出哦
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 飘絮絮絮丶
    专家
戳我,来吐槽~