原标题:组复制性能 | 全方位认识 MySQL 8.0 Group Replication


本节介绍如何使用可用的系统变量对组复制进行性能优化,以便获得最佳性能。6.1. 微调组通信线程当加载并启动MGR插件时,组通信线程(GCT)就会不断循环运行。 GCT接收来自组和MGR插件的消息,处理与仲裁和故障检测相关的任务,发送一些保活的通讯消息,还处理MySQL Server与组之间传入和传出的事务。GCT会等待队列中的传入消息。当队列中没有消息时,GCT将会进行等待。在某些情况下,通过将这个等待配置得稍微长一些(进行主动等待),可以减少操作系统执行上下文切换时从处理器中换出GCT线程的次数。要强制GCT执行主动等待,请使用系统变量group_replication_poll_spin_loops进行设置,这使得 GCT 在对下一个消息进行实际轮询队列之前,在已配置的循环次数内进行循环时不做任何相关操作(该系统变量设置的值表示需要等待通信引擎互斥锁(mutex)被释放的次数,不是时间单位)。
mysql> SETGLOBALgroup_replication_poll_spin_loops= 10000;
6.2. 流量控制组复制可确保事务仅在组中的大多数成员接收到它,且并发发送的所有事务在所有接收到事务的成员之间的相对顺序达成一致后,就可以执行事务的提交操作。 如果对组的写入并发事务总数不超过组中任何成员的写入容量(提供写服务的能力),则此方法可以获得很好的性能。但如果组中所有成员能够提供的最大写服务能力不相同,那么组中服务能力低的成员可能出现数据延迟(例如:一些成员能提供3000TPS的写能力,但是有一些成员只能提供2000TPS的写能力),那么,当对能够提供3000TPS的成员写入并发3000的事务时,只能提供2000TPS的成员就会出现延迟(数据落后于能够提供3000TPS的成员)。组中如果有成员出现数据延迟,将有可能导致应用程序对这些成员执行读操作时,读取到非常陈旧的数据,另外,组中的其他不存在数据延迟的成员或多或少需要保存一些复制上下文(binlog日志记录),以满足来自存在数据延迟的慢速成员潜在的数据传输请求。 但是,复制协议中有一种机制可以避免在快成员和慢成员之间存在过大的事务差距。这就是所谓的流量控制机制。流量控制机制图解决如下几个问题:
- 保持成员之间的数据足够接近(慢速成员没有太大数据延迟)。
- 快速适应组中不断变化的环境。 如,适应不同的工作负载或更多写操作。
- 让组中的每个成员能够提供的写服务能力得到一个平衡。
- 在非严格必要的情况下,不降低吞吐量,以避免浪费资源。
- 对组成员进行监控,并收集所有组成员的吞吐量和队列大小的一些统计信息,从而对每个组成员能够承受的最大写压力进行有根据的猜测(评估);
- 对组中的所有成员的并发写能力时刻保持监控,一旦某成员的并发压力超过了组中所有成员的平均写能力,就会对其执行流量控制。
- 认证队列大小
- 复制应用队列大小
- 认证完成的事务总数
- 组成员中应用的远程事务的总数
- 本地事务的总数
| 工作负载模拟程序 | 行格式压缩比例 | 语句格式压缩比例 |
|---|---|---|
| mysqlslapd | 4,5 | 4,1 |
| sysbench | 3,4 | 2,9 |

MGR 插件架构如上图所示,压缩功能在插件的五层(位于MySQL Server和复制组之间,刨去MySQL Server层,它是MGR插件的第四层,也就是组通讯引擎层)。 压缩和解压缩的工作任务由组通信系统API处理。压缩发生在数据被传递给组通信线程之前的组通讯引擎,所以它发生在MySQL 用户会话线程的上下文中。事务有效负载可能在发送到组之前进行压缩,在接收之后进行解压缩。压缩是有条件的,并且依赖于一个配置的阈值。压缩功能默认启用。此外,并不要求组中的所有成员都启用压缩来协同工作。 在收到消息后,成员会检查消息信封以验证它是否已被压缩。如果需要,则该成员在将事务交付给上层组件之前会对其进行解压。使用的压缩算法是LZ4。 默认情况下启用压缩,阈值为1000000字节(1M)。压缩阈值(以字节为单位)可以根据需要设置为比默认值更大的值。当压缩阈值不为0时,只有有效负载大于阈值的事务才会被压缩。设置压缩阈值示例如下:
# 这将压缩阈值设置为2MB。如果事务生成的复制消息的有效负载大于2MB,例如:二进制日志事务条目大于2MB,则对其进行压缩。若要禁用压缩,请将阈值设置为0。
STOPGROUP_REPLICATION;
SETGLOBALgroup_replication_compression_threshold= 2097152;
STARTGROUP_REPLICATION;
6.4. 消息分段当在组复制组成员之间发送异常大的消息时,可能导致某些组成员发生失败并被驱逐出组。 这是因为组复制的组通信引擎(XCom, Paxos变体)使用的单个线程占用的处理消息的时间太长,因此某些组成员可能会报告消息接收失败。默认情况下,从MySQL 8.0.16开始,大的消息被自动分割成片段,分别发送,然后由接收者重新组合这些消息片段。系统变量group_replication_communication_max_message_size指定组复制通信的最大消息大小,超过该大小的消息将被分段。 默认的最大消息大小是10485760字节(10 MiB)。该系统变量的最大允许值与系统变量slave_max_allowed_packet的最大值相同(后者是1073741824字节,即 1GB),系统变量group_replication_communication_max_message_size的设置值必须小于系统变量slave_max_allowed_packet的设置值,因为应用线程不能处理大于系统变量slave_max_allowed_packet的消息片段。要关闭消息分段功能,请将系统变量group_replication_communication_max_message_size设置为零值。与大多数其他组复制系统变量一样,修改系统变量group_replication_communication_max_message_size必须重新启动组复制才能使更改生效。 例如:
STOPGROUP_REPLICATION;
SETGLOBALgroup_replication_communication_max_message_size= 5242880;
STARTGROUP_REPLICATION;
当所有组成员都接收并重新组合了消息的所有片段时,就认为分段消息的消息传递已经完成了。 分段消息的头部包含了一些信息,这些信息使成员能够在消息传输期间加入组,并恢复加入组之前发送的早期消息片段。如果joiner节点无法恢复消息片段,则会将自己从组中驱逐出去。
为了让一个复制组正常使用消息分段功能,所有组成员必须运行MySQL 8.0.16或以上版本,并且组使用的组复制通信协议版本必须支持消息分段。可以使用group_replication_get_communication_protocol UDF检查组使用的通信协议版本是多少,UDF 返回版本号字符串代表了组支持的最老的MySQL Server版本。MySQL 5.7.14的版本支持压缩消息,MySQL 8.0.16的版本支持消息分段。如果所有组成员都运行在MySQL 8.0.16以上版本,并且组中不需要运行更低版本的组成员,则可以使用group_replication_set_communication_protocol UDF来设置通信协议版本为MySQL 8.0.16及其以上,这样就能够确保消息分段功能在组中所有成员上正常运行。有关更多信息,请参见”4.1.4. 设置组的通信协议版本”。
如果复制组由于某些成员不支持消息分段导致组不能使用消息分段,则可以使用系统变量group_replication_transaction_size_limit来限制该组所接受的最大事务大小。在MySQL 8.0中,默认设置大约为143 MB。超过这个大小的事务将被回滚。还可以使用系统变量group_replication_member_expel_timeout来设置一个在成员被驱逐出组之前,它被怀疑失败的额外时间(默认为0,从8.0.14版本开始,最大值为一个小时)。即,在该系统变量设置的时间内,被怀疑的成员不会被驱逐出组。
6.5. XCom 缓存管理用于组复制的组通信引擎(XCom, Paxos变体)包含了一个消息(及其元数据)缓存,该消息是作为组成员之间交换协商一致性协议的一部分。 在其他用途中,消息缓存可用于在一段时间内无法与其他组成员通信的成员在重新返回到组时进行恢复。从MySQL 8.0.16开始,可以使用系统变量group_replication_message_cache_size为XCom的消息缓存设置缓存大小限制。 这个系统变量的默认值和最小值为1 GB,即MySQL Server 8.0.16 版本之前的消息缓存大小设置。如果达到了缓存大小限制设置,XCom将删除已经确定和交付的最老的条目。考虑到MySQL Server的其他缓存和对象池的大小,请确保在系统上有足够的内存来满足所设置的缓存大小限制。如果一个不可达成员尝试重新恢复连接时,需要一条恢复消息,但该消息已从消息缓存中删除,则该成员无法重新连接。 如果使用了系统变量group_replication_member_expel_timeout(该系统变量在MySQL 8.0.13中引入)指定一个额外的延迟时间,则更有可能出现这种情况。当不可达的成员恢复时可能需要使用到的消息在消息缓存中已经被删除时,组复制的组通信系统(GCS)通过一条警告消息来发出警告。此警告消息记录在所有活跃的组成员上(对于每个不可到达的成员仅记录一次)。尽管组成员不能确定不可到达的成员最后看到的消息是什么消息,但是警告消息表明缓存大小可能不足以支撑通过系统变量group_replication_member_expel_timeout设置的在驱逐成员之前的等待时间内总的消息大小。在这种情况下,可以增加缓存大小限制,以便消息缓存能够存放组成员重新加入组所需的所有遗漏消息。如果考虑减少缓存大小限制,可以使用以下语句先查询performance_schema.memory_summary_global_by_event_name表中记录的相关内存分配情况:
# 查询语句返回消息缓存的内存使用统计信息,包括当前缓存条目的数量和当前缓存的大小。如果降低了缓存大小限制,XCom将删除已经确定并交付的最老的条目,直到当前大小低于限制值为止。在删除最老的条目过程进行期间,XCom可能会暂时超过缓存大小限制。
mysql> SELECT* FROMperformance_schema.memory_summary_global_by_event_name
WHEREEVENT_NAME LIKE‘memory/group_rpl/GCS_XCom::xcom_cache’;
6.6. 对故障检测和网络分区的响应组 复制的故障检测机制旨在识别不能与组正常通信的组成员,并在他们可能发生故障时将他们从组中驱逐出去。当组中有成员发生故障时,如果组中存在多数成员存活,则故障检测机制能够使得组正确恢复可用性,以便能够及时恢复并正确处理客户端的请求。通常,所有组成员会定期与所有其他组成员交换消息。 如果一个组成员在5秒内没有收到来自某个特定成员的任何消息,当这个检测周期结束时,就会产生对该成员的怀疑。当一个可疑成员超时时(在最大允许的怀疑时间范围内仍然没有任何消息),该可疑成员就被认定为失败了,并被驱逐出组。被驱逐的成员会被组中所有活跃成员从组成员资格列表中删除,但被驱逐的成员自己可能不知道已经被驱逐出组(例如:它自己还在线,只是无法联系其他成员)。如果被驱逐的成员实际上没有失败(例如,因为临时网络问题而断开连接),并且后续能够恢复与其他成员的正常通信,则在网络恢复之后它会收到一个包含了该成员已被驱逐出该组的新视图信息。组成员(包括失败的成员本身)对这些情况的响应可以在流程中的许多地方进行配置。 默认情况下,如果怀疑某个成员失败,则会发生以下行为:
- 当创建怀疑对象时,它将立即超时(其生存期设置为0),因此一旦怀疑对象发生超时,嫌疑成员就会被驱逐。 成员可能在超时后继续存活几秒钟,因为对怀疑对象的检查是周期性的。
- 如果被驱逐的成员恢复了正常通讯,并意识到自己被驱逐了,它就不会试图重新加入到该组,而会接受驱逐结果。
- 当一个被驱逐的成员接受它的驱逐结果时,它就会切换到超级只读模式(设置super_read_only=1。 注意:设置super_read_only=ON时,read_only会自动设置为ON,但在将super_read_only=OFF时,不会自动将read_only设置为OFF),直到人工介入处理(注意:在MySQL 8.0.12到8.0.15的版本中,组成员被驱逐时默认的行为是关闭自身数据库进程。从MySQL 8.0.16开始,默认行为被更改为匹配MySQL 5.7中的行为,即,设置超级只读模式)。
- 在一个对称的组中,例如有两个或四个成员的组,如果两个网络分区都包含了相同数量的成员,则两个组部分都会认为自己属于少数派,并都会进入ERROR状态。 在这种情况下,组没有任何一个网络分区可用(即,没有任何一个被网络拆分的组部分可用正常对外提供服务)。
- 当存在少数派的组部分时,少数派组部分处理的任何事务都将被接受(不会被拒绝),但会被阻塞,因为少数派组部分的成员无法达到法定人数(即,不满足达成共识所需的多数成员要求),直到在这些成员上执行STOP GROUP_REPLICATION语句,或处于这种状态达到超时之后自动处理脱离组操作为止。
- 如果没有设置与多数成员失联超时,则少数派组部分中的成员将永远不会自动进入ERROR状态,此时,你必须手动停止它们。
- 如果在检测到与多数成员失联超时之后,再到少数派成员上设置与多数成员失联超时的设置,则此时设置无效,需要提前设置才会生效。
- 如果退出操作配置为READ_ONLY,则会通过将系统变量super_read_only设置为ON,以便将MySQL切换到超级只读模式。 当成员处于超级只读模式时,客户端不能执行任何更新操作,即使他们拥有super权限。但是,客户端仍然可以读取数据,由于数据不再更新,所以,随着时间的推移,读取到陈旧的数据的概率会大大增加。因此,使用此设置时,需要主动监控Server的故障状态。该退出操作也是MySQL 8.0.16及其之后版本的默认操作。执行此退出操作后,成员的状态将在组视图中显示为ERROR状态。
- 如果退出操作配置为OFFLINE_MODE,则会通过将系统变量offline_mode设置为ON,以便将MySQL切换到离线模式。 当成员处于离线模式时,连接的客户端用户执行下一个请求时连接会被断开,且不再接受其新的连接请求,只接受具有CONNECTION_ADMIN或super权限的用户建立新的客户端连接。组复制还会将系统变量super_read_only设置为ON,以阻止普通用户与超级用户执行更新操作。此退出操作可以防止更新操作,也可以防止读取到陈旧的数据(因为普通用户无法再次建立连接,但具有指定权限的客户端用户如果要在这个时候执行查询,则仍然可能读取到陈旧的数据)。同时允许MySQL Server继续运行,以便管理员可以尝试解决问题而不关闭MySQL Server进程。此退出操作在MySQL 8.0.18中可用。在执行此退出操作之后,成员的状态将在组视图中显示为ERROR状态(不是OFFLINE,这意味着MGR插件可用,但该成员当前它不属于组)。
- 如果退出操作配置为ABORT_SERVER,则MySQL Server将被关闭。 虽然这可以防止所有的更新操作和读取陈旧的数据,但也意味着MySQL Server不可用,必须重新启动Server进程。该退出操作在MySQL 8.0.12版本中引入,且在大于等于8.0.12与小于等于8.0.15之间的版本中为默认的退出操作。执行此退出操作后,退出成员将被从组视图列表中删除。
- 无论设置什么退出操作,当执行完退出操作之后,都需要人为介入对其进行恢复,此时,不人为执行重启组复制的情况下不允许(也无法)重新加入组。
- 如果Server在成功加入组之前发生失败(从未成功加入组的Server),则不会执行group_replication_exit_state_action系统变量指定的退出操作。 例如,在本地配置检查期间出现故障、或者joiner节点的配置与组的配置不匹配,就会出现这种情况。在这些情况下,系统变量super_read_only将保持原始值(不会进行调整),MySQL Server也不会执行关闭动作(当然,此时由于该Server未成功加入组,所以也就无法接受组中的更新数据,此时如果在该Server中发生新的数据写入,将导致后续难以将这些新数据同步到组中)。所以,为了避免这种情况的发生,建议在启动时在配置文件中设置系统变量super_read_only=ON,当配置好组复制之后,会自动将系统变量super_read_only设置为OFF。
- 应用线程错误: 复制应用线程中存在错误。此问题不可自动恢复。
- 无法执行分布式恢复: 这意味着无法完成组复制的分布式恢复过程(即,无法使用基于远程克隆操作和基于二进制日志的状态传输)。组复制在这种情况下会自动重试分布式恢复,但如果没有其他更多选择来完成该过程,则组复制将停止。具体参见”4.3.3. 分布式恢复的容错能力”。
- 组配置变更时发生错误: 在使用UDF进行组范围的配置变更期间发生错误,详见”4.1. 在线配置组”。
- 选主期间发生错误: 在以单主模式运行的组中,执行选主时发生错误,详见”1.3.1. 单主模式”。
- 与多数成员失联超时: 该成员已与大多数组成员失去联系,因此它属于少数成员的组部分,且系统变量group_replication_unreachable_majority_timeout设置的超时时间已过期(与多数成员失联时间已超过该系统变量设置的时间)。
- 被驱逐出组的成员: 组中的其他成员对该成员产生了怀疑,且系统变量group_replication_member_expel_timeout设置的超时已过期(怀疑期超时时间),当该成员恢复与组的通信之后会发现自己已被驱逐出组。
- 尝试自动重新加入组的次数耗尽: 当某个成员与组中的其他大多数成员失联或被驱逐出组之后,会根据系统变量group_replication_autorejoin_tries设置的次数不断尝试自动重新加入组,当该成员耗尽了尝试次数,也仍然能未能成功加入组。
| 失败的场景 | 使用START GROUP_REPLICATION语句启动组复制 | 启用系统变量group_replication_start_on_boot =ON使组复制随数据库进程一并启动 |
|---|---|---|
|
|
同左 |
|
|
同左 |
- 成员本地配置检查失败
- 加入组的成员与组配置不匹配
- 系统变量super_read_only和offline_mode值保持不变
- 允许MySQL Server继续运行
- 在启动时设置系统变量super_read_only=ON以防止更新
- 成员上的应用线程错误
- 分布式恢复不可用
- 组配置进行了错误的修改
- 选主出错
- 多数成员不可达超时
- 被驱逐出组的成员
- 超过自动重新加入组尝试次数仍未成功加入组的成员
- 系统变量super_read_only设置为ON 或
- 系统变量offline_mode和super_read_only设置为ON 或
- MySQL Server关闭
| 作者简介
罗小波·数据库技术专家
《千金良方——MySQL性能优化金字塔法则》作者之一。熟悉MySQL体系结构,擅长数据库的整体调优,喜好专研开源技术,并热衷于开源技术的推广,在线上线下做过多次公开的数据库专题分享,发表过近100篇数据库相关的研究文章。
延伸阅读
责任编辑: