vlambda博客
学习文章列表

组复制要求和限制 | 全方位认识 MySQL 8.0 Group Replication



组复制要求和限制 | 全方位认识 MySQL 8.0 Group Replication

// 9.1. 组复制要求

基础设施要求

  • InnoDB存储引擎:必须使用InnoDB存储引擎来存取数据。采用乐观锁方式,事务在提交时检测是否存在冲突,如果存在冲突,则为了保证整个组中数据的一致性,会回滚一些事务(存在冲突的事务中,先提交的事务不会受到影响,继续完成提交,而后提交的事务会被回滚),这意味着需要支持事务的存储引擎。此外,InnoDB还提供了一些附加功能,InnoDB存储引擎与组复制一起工作时能更好地管理和处理事务冲突。如果使用其他存储引擎,则可能会由于不支持这些功能与特性,无法正确处理组中的冲突等而发生错误。可以通过系统变量disabled_storage_engines来关闭其他不适用于组复制的存储引擎,如:

    disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"。

  • 主键:复制组中的每个表必须定义一个主键,或者定义一个与主键等效的非空唯一键,因为组复制需要利用唯一键来作为表中的每一行数据的唯一标识符,从而使得组能够准确地确定每个事务修改了哪些行,以便能够判断哪些事务存在冲突。

  • 网络性能:组复制的设计要求一个组中的成员之间的物理距离不能太远(网络传输距离)。长距传输时的网络时延和网络带宽都会影响组的性能和稳定性。因为,组中的所有组成员之间必须始终保持双向通信(默认情况下,每秒都会相互发包探测其他组成员的健康状况)。如果是跨IDC机房的,防火墙策略需要在组复制组成员之间开通它们相互通讯所需的所有端口,否则被阻塞的成员会因为无法正确向组报告其Server的状态而被驱逐出组。从MySQL 8.0.14版本开始,可以使用IPv4或IPv6或两者混合使用来进行组成员之间的TCP通讯,也支持在虚拟专用网(VPN)上运行组复制。另外,在MySQL 8.0.14版本中,当组复制的成员位于同一位置(同一台主机)时,如果可能,则可以共享一个本地的组通信引擎(XCom)实例,这样,使用一个专用的开销更低的输入通道相比于使用TCP套接字进行通讯,能够最大程度地提高组的性能。但对于某些需要在远程XCom实例之间通信的组复制任务(例如:新的Server加入一个组),则仍然会使用TCP网络通讯,但此时网络性能会影响组的性能。

Server的系统变量配置要求

  • 启用二进制日志记录功能:通过系统变量log-bin [= log_file_name]进行配置(例如:log_bin=mysql-bin)。组复制的数据同步机制是基于主从复制的基础架构实现的,需要使用二进制日志来进行数据同步,因此必须启用二进制日志才能进行操作。该系统变量默认启用(MySQL 8.0版本默认启用,在更早的版本中,该系统变量默认关闭)。

  • 从库的任何更新都要记录到二进制日志中(包括通过复制同步的更新):通过系统变量log-slave-updates进行配置(例如:log_slave_updates=1)。该系统变量默认启用(>= 8.0.3版本默认启用,<= 8.0.2版本默认关闭 )。每个组成员都会记录加入组时从donor节点接收并应用的事务日志(二进制日志),也会记录其成功加入组之后从组中接收和应用的所有事务(二进制日志),这样,当有其他Server申请加入组时,组中的任意现有成员才能够为其提供基于二进制日志的状态传输来进行分布式恢复。

  • 使用row(行)格式的二进制日志:通过系统变量binlog-format =row进行配置(例如:binlog_format=row)。组复制基于行的复制格式来实现组成员之间同步数据的一致性。它依赖于基于行的基础结构,以便能够从基于行的二进制日志中提取出必要的信息来检测在组中不同组成员上并发执行的事务之间是否存在冲突。

  • 关闭二进制日志checksum校验:通过系统变量binlog-checksum=NONE进行配置(例如:binlog_checksum=NONE)。由于复制事件校验机制的设计限制,组复制不支持二进制日志事件的checksum校验,所以必须禁用。

  • 启用全局事务标识符(GTID):通过系统变量gtid-mode=ON进行配置(例如:gtid_mode=ON)。组复制使用全局事务标识符精确地跟踪每个组成员上已提交的事务,从而能够推断哪些组成员执行的事务可能与其他位置中已经提交的事务发生冲突。

  • 复制信息存储到表:通过两个系统变量master_info_repository=TABLE和relay_log_info_repository=TABLE进行配置。复制线程需要将主库的连接信息、同步主库的位置信息息和中继日志元数据信息写入到mysql.slave_master_info和mysql.slave_relay_log_info系统表中存放。这确保了组复制能够通过复制的元数据信息来实现事务管理和一致性恢复。从MySQL 8.0.2版本开始,这两个系统变量默认值为TABLE(>=8.0.2版本默认值为TABLE,<=8.0.1版本默认值为FILE),从MySQL 8.0.3版本开始,不再推荐使用FILE设置值。

  • 事务写集(write set)提取:通过系统变量transaction-write-set-extraction=XXHASH64配置用于生成写集的hash算法。组成员在将row格式的二进制日志记录到二进制文件的同时,也会收集写集。写集是基于row格式的二进制日志中每一行数据变更中可以唯一标识数据行的主键值(或唯一键值)生成的一个简单紧凑的视图标记。通过这个标记就能够进行事务的冲突认证检测。该系统变量默认启用(>=8.0.2版本默认为XXHASH64,<=8.0.1版本默认值为OFF)。

  • 默认表加密:通过系统变量default_table_encryption=ON配置,组中所有的成员需要设置为相同的值,这样,就可以启用(ON)或禁用(OFF,默认值也为OFF)在组中默认对库和表空间的默认加密设置(当启用该系统变量时,如果用户在创建库或表时,没有指定ENCRYPTION选项,则该系统变量的设置对库表生效,即,启用加密)。注意:该系统变量在MySQL 8.0.16版本引入,可以动态修改。仅对用户创建的库表生效。

  • 表名称小写:通过系统变量lower_case_table_names=1设置,组中的所有成员需要设置为相同的值。在组复制中使用InnoDB存储引擎时,需要将该值设置为1(将表名称都转换为小写)。注意,该系统变量的默认值在不同的平台上有不同的默认值(在Windows上,默认值为1,在OS X上,默认值为2,在类UNIX系统上,默认值为0)。

  • 多线程复制:可以为组复制的成员启用多线程复制,从而使事务能够在组中的远端节点执行并行应用(发起事务写入的节点可以称为本地节点,其他通过二进制日志进行数据同步的节点可以称为远端节点)。通过将系统变量slave_parallel_workers设置为一个非0值来启用组成员上的多线程复制(设置为0表示禁用多线程复制,此时,系统变量slave_parallel_type和slave_preserve_commit_order的设置不生效),最多可以指定1024个并行应用线程(worker线程)。设置系统变量slave_preserve_commit_order=1可确保并行应用事务的最终提交顺序(这里指的是远端节点)与复制组所要求的原始事务的提交顺序相同(这里指的是本地节点提交事务之后,在组复制插件中排序的全局顺序),组复制的一致性保证依赖于组中所有的成员按照相同的顺序接收并应用组中已提交的事务。最后,设置系统变量slave_preserve_commit_order=1需要同时设置系统变量slave_parallel_type=LOGICAL_CLOCK,它用于确定哪些事务可以在从库上并行执行的策略。 

    * PS:通过前面的章节我们可以知道,组复制是基于主从复制的基础架构实现的,但相对于主从复制的IO和SQL线程来讲,组复制中对原来接收主库二进制日志的IO线程改动较大(用了一些后台线程相互协作来代替了主从复制拓扑中的IO线程的功能),对解析二进制日志并进行回放的SQL线程(或者说协调器线程与worker线程)改动较小。每一个组成员中都会创建到组复制的连接(主从复制拓扑中的IO线程被替换为了一些接收、验证写集的一些后台线程,可通过performance_schema.threads表进行查看),每一个组成员对接收到的写集进行冲突认证检测,并将认证通过的写集(二进制日志)写入自身的中继日志中,然后,由SQL线程读取中继日志进行回放(多线程复制中,由协调器线程读取中继日志,然后并行分发给worker线程进行回放)。

PS:组复制中所有组成员的Server 都必须满足以上要求

// 9.2. 组复制限制

组复制存在以下已知的限制。

  • 注意: 

    * 在故障转移期间,对于多主模式的组所描述的限制和问题同样也适用于单主模式的组(新当选的主要节点从旧的主要节点清空其应用队列时,在这个临界点,可以将其类比组复制中有2个成员可写,所以这个时候单主模式也需要遵循多主复制模式中的限制) 。

    * 组复制的实现依赖于GTID复制机制,因此,组复制的限制还需要考虑到GTID复制的限制。


--upgrade=minimal:当MySQL Server指定--upgrade=minimal选项启动时,如果发现需要执行更新,则,在执行升级操作完成之后,可能会导致组复制无法启动,因为minimal选项在执行更新时,只会更新数据字典、information_schema、performance_schema,但不会更新组复制内部所依赖的系统表(--upgrade选项在MySQL 8.0.16版本引入,之后,升级操作将不再需要单独使用mysql_upgrade工具,默认情况下--upgrade选项值为AUTO,表示自动判断是否需要执行完整的更新操作)。
间隙锁(gap locks):冲突认证检测过程不考虑间隙锁,因为有关间隙锁的信息在InnoDB存储引擎之外是不可用的。有关更多信息,请参见" https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-gap-locks "。
  • 注意:除非您的应用程序依赖于RR隔离级别,否则在组复制中建议使用RC隔离级别。因为InnoDB存储引擎在RC隔离级别中没有间隙锁,这就使得InnoDB存储引擎中的本地冲突检测与组复制执行的分布式冲突检测能够对齐(保持一致)。

表锁和命名锁:冲突认证检测过程不考虑表锁(表锁指的是:使用lock...table语句加锁、使用unlock table语句解锁)或命名锁(命名锁指的是:使用GET_LOCK()函数创建、使用RELEASE_LOCK()函数释放的锁)。
复制事件的checksum校验:由于复制事件的checksum校验机制的设计限制(这里指的是binlog中对每个event的checksum校验),组复制目前不支持。因此需要禁用(使用系统变量binlog-checksum=NONE关闭)。
可序列化(SERIALIZABLE)的隔离级别:默认情况下,多主模式的组不支持 SERIALIZABLE 隔离级别。将事务隔离级别设置为SERIALIZABLE时,组复制将拒绝该事务提交。

执行DDL语句期间并行执行DML语句:在多主模式的组中,不支持在不同的组成员上对同一个数据库对象并行执行DDL和DML语句。因为,对于某个对象来说,如果在一个组成员上执行DDL语句期间,同时在另外一个组成员上针对该对象并行执行DML语句,则,在组复制中可能导致DDL冲突无法被检测到的风险。

  • 注意:在同一个组成员中对同一个对象并行执行DDL和DML语句,会由本地Server自行通过锁进行管理,不需要组参与。
具有级联约束的外键:多主模式的组(所有成员都设置了系统变量group_replication_single_primary_mode=OFF)不支持具有多级外键依赖关系的表,尤其是定义了级联外键约束的表。外键约束可能导致组无法检测到某些冲突,进而导致组成员之间的数据不一致。因此,建议在多主模式的组中所有组成员都设置系统变量group_replication_enforce_update_everywhere_checks=ON(启用该系统变量之后,一些可能带来风险的操作将直接被拒绝) ,以避免一些可能存在的冲突无法被检测到。注:在单主模式下,不存在这个问题,因为单主模式中,只有一个主要节点允许写操作。
多主模式死锁:当一个组在多主模式下运行时,SELECT..FOR UPDATE语句会导致死锁。这是因为在组成员之间无法共享锁。
复制过滤器:不能在组复制的成员中对组复制专用的group_replication_applier或group_replication_recovery通道配置使用全局复制过滤器,因为在某些组成员上过滤了事务会破坏组中所有成员之间的数据一致性。但是,如果某个组成员同时作为主从复制拓扑中的从库时,则该主从复制通道允许配置使用全局复制过滤器(这里的主从复制通道,不包括组复制专用的group_replication_applier或group_replication_recovery通道)。
加密连接:从MySQL 8.0.16版本开始,MySQL Server支持TLSv1.3协议(前提是MySQL Server是使用OpenSSL 1.1.1或更高版本编译的)。但,从MySQL 8.0.18版本开始,组复制才支持TLSv1.3协议。所以,在MySQL 8.0.16和MySQL 8.0.17版本中,虽然MySQL Server支持TLSv1.3协议,但由于组通信引擎不支持TLSv1.3版本协议,所以,组复制在这两个Server版本中仍然不能使用TLSv1.3协议。
  • 如果在组复制中使用了TLSv1.3版本协议进行分布式恢复,则组复制的组成员中至少一个成员必须允许使用TLSv1.3版本协议的密码套件。
组成员的数量限制:单个复制组中允许的组成员(MySQL Server实例)最大数量是9个。如果有更多的Server尝试加入该组时,其连接请求将被拒绝。该限制数量是通过已有的测试案例和基准测试中得出的一个安全边界,在这个安全边界中,组能够安全、可靠、稳定地运行在一个局域网中。
事务大小限制:如果单个事务产生的消息内容过大,以至于通过网络无法在5秒的时间内在组成员之间成功复制消息时,则可能会怀疑该成员失败了,进而导致其被驱逐出组,因为事务过大可能导致该成员一直忙于处理事务或者由于事务过大导致内存分配问题,进而导致系统变慢。为避免这些问题,可以采用以下措施进行适当缓解:
  • 如果由于消息过大而导致发生了不必要的驱逐,那么可以使用系统变量group_replication_member_expel_timeout来为被怀疑失败的成员在被驱逐出组之前设置一个额外的等待时间(缓冲时间)。在最初的5秒钟检测期之后,会按照该系统变量设置的时间进行等待而不立即执行驱逐(最多一个小时),但是,当超过该系统变量设置的怀疑等待时间之后成员仍然未恢复组通讯的,则仍然会被驱逐出组。
  • 在可能的情况下,请尝试限制组复制中的事务大小。例如:使用LOAD DATA语句加载一个大文件之前,先将这个大文件拆分为小文件进行逐个加载。
  • 使用系统变量group_replication_transaction_size_limit设置复制组允许接收的最大事务大小。在MySQL 8.0中,该系统变量的默认最大事务大小为150000000字节(大约143 MB)。超过此大小的事务将被回滚,并且不会将该事务发送到组复制的组通信系统(GCS)中进行分发。请根据你的实际情况调整该系统变量的大小(注意:处理事务的时长与事务的大小成正比)。
  • 使用系统变量group_replication_compression_threshold指定一个消息大小,当消息大小超过该系统变量设置的值时将被执行压缩。该系统变量默认为1000000字节(1 MB),大于该系统变量大小的消息将被组复制的组通信系统(GCS)自动压缩(消息大小大于系统变量group_replication_compression_threshold设置的值但小于系统变量group_replication_transaction_size_limit设置的值时,消息才会被执行压缩)。有关更多信息,请参见"6.3. 消息压缩"。
  • 使用系统变量group_replication_communication_max_message_size指定一个消息大小,当消息大小超过该系统变量设置的值时将被执行分段。 该系统变量的默认值是10485760字节(10 MiB),因此超过 该大小的消息将会被自动分段(如果压缩后的消息仍然超过group_replication_communication_max_message_size系统变量设置的限制大小,则GCS在压缩完成之后再执行消息分段,每一个消息段的大小即为该系统变量设置的大小)。 如果要使用消息分段,则组中所有的成员必须使用MySQL 8.0.16以上的版本,且组中的组复制通讯协议版本也必须要支持消息分段。 有关更多信息,请参见"6.4. 消息分段"。

如果将以上组复制相关的限制性的系统变量值设置为0值,则表示禁用这些限制(事务大小限制、消息大小限制、消息分段限制等)。即,这就意味着关闭了所有这些保障措施。此时,组复制的每个成员可以处理的消息大小上限为每个成员中的系统变量slave_max_allowed_packet的值,,该系统变量的默认值为1073741824字节(1 GB,也是该系统变量的最大值)。超过该系统变量设置的消息大小的事务将失败。另外,单纯针对复制组来说,组成员可以发起并尝试传输给组的最大消息大小限制是4294967295字节(大约4 GB)。这是组复制(Paxos变体,XCom)的组通信引擎所能接收的包大小的硬限制。当有组成员试图广播超过这个硬限制大小的消息时将会广播失败。


| 作者简介

罗小波·数据库技术专家

《千金良方——MySQL性能优化金字塔法则》、《数据生态:MySQL复制技术与生产实践》作者之一。熟悉MySQL体系结构,擅长数据库的整体调优,喜好专研开源技术,并热衷于开源技术的推广,在线上线下做过多次公开的数据库专题分享,发表过近100篇数据库相关的研究文章。

全文完。


Enjoy MySQL 8.0 :)


老叶茶馆推荐搜索
MGR
MySQL8
ClickHouse
InnoDB


叶老师的「MySQL核心优化」大课已升级到MySQL 8.0,扫码开启MySQL 8.0修行之旅吧