组复制部署完成后,即进入日常运维阶段。你需要监控各成员的运行状态,并在必要的时候还需要进行一些调整操作。
一、组复制监控
1.1 组复制成员状态
在组复制运行中,成员可能处于以下几种状态:
online 在线,成员处于正常运行状态并可提供服务。
recovering 恢复中,成员正在从其他捐赠者获取事务并恢复中。
offline 离线,组复制插件已加载,但还未加入任何一个组,只有在离线成员上查询才能看到offline,其他成员看不到(因为还没加入组)。
error 错误,成员在恢复阶段或同步阶段出现错误,只有在错误成员上查询才能看到error,其他成员看不到。
unreachable,不可达,成员无法与其他成员通信。
当成员安装组复制插件后,状态为offline。当其加入一个组时,会选择一名成员作为捐赠者(Donor),获取事务信息并开始恢复,此时状态为recovering,恢复成功后,成员加入组,状态变为online。如果在recovering阶段出错,其状态将变为error,而其他成员上会发现刚才处于recovering状态的成员已经被移除。
组复制正常运行时,如果某个online成员通信异常,则在其他的成员上会发现其状态是unreachable(不可达),如果unreachable成员在规定的超时时间内未恢复,那么它将从组中移除。
1.2 组复制监控
组复制的状态主要是通过performance_schema下几张相关的表进行监控的:
performance_schema.replication_group_members
主要监控组成员的状态,当视图发生变更时,就会更新该表中的信息。
performance_schema.replication_group_member_stats
每个组成员都会从组接收、验证并应用事务。改表提供与事务验证与应用相关的信息,及每个成员接收和发起事务的统计信息。
performance_schema.replication_connection_status
显示有关组复制的信息,例如从组中接收并在排队中的事务。
performance_schema.replication_applier_status
显示与组复制相关的通道和线程状态。与组复制相关的通道线程有2个:
group_replication_recovery,用于分布式恢复的线程
group_replication_applier,用于应用从组接收到的事务的线程。
以上4张表中,replication_group_member_stats对监控组复制的性能较为重要,其信息在所有成员中共享,所有成员上的查询结果应该是相同的。当发生变化时,信息会在所有的成员上刷新,刷新频率由group_replication_flow_control_period(默认1秒)控制。如果发现某个成员队列中有大量的排队事务,说明其存在较高延迟,无法与其他成员同步。有可能将其从组中踢出或延迟处理事务,以减少排队中事务的数量。
二、组复制运维
MySQL 8.0.13及更高的版本中,可以通过一系列函数来调整组复制配置,你可以从任何一个处于online状态的成员上通过select语句调用这些函数。而具体操作将通过一个协调器(Group Action Coordinator)传递给所有的组成员,每名组成员完成后会返还一个确认信息,当接收到所有成员的确认信息后,操作成功并返回。
2.1 变更主库
在单主模式中,你可以通过函数group_replication_set_as_primary(uuid)来指定某台服务器成为主库,在完成主库切换前,当前主库会等待所有运行中的事务完成(提交或回滚)。并且切换申请提交后,依然可以发起新的事务,如果系统持续有事务运行,那么这个切换动作可能会无限制的等待下去。因此服务器角色前建议先暂时事务活动。MySQL 8.0.29以后的版本可以指定第二个参数,超时时间。
下面示例中,当前的主库是slave01,通过指定member_id,我们将主库切换为master
select* from performance_schema.replication_group_members;
selectgroup_replication_set_as_primary('d0b9b72b-67c9-11ed-87b2-0800276c19d8'); -- 这里填的是目标主库的UUID
再次查询角色,master角色已经变为主库,slave01的角色变成了secondary,切换成功:
select* from performance_schema.replication_group_members;
MySQL 8.0.29以后的版本,可以指定第二个参数,超时时间:
selectgroup_replication_set_as_primary('d0b9b72b-67c9-11ed-87b2-0800276c19d8',300); -- 这里指定超时为300秒,防止无限等待
2.2 切换至多主模式
通过调用函数group_replication_switch_to_multi_primary_mode(),可以从单主模式切换到多主模式:
select group_replication_switch_to_multi_primary_mode();
通过查询成员表,可以看到所有成员的角色都变成了primary,此时所有成员都可接收事务:
select* from performance_schema.replication_group_members;
如果切换的时间较漫长,可以通过下列SQL查询当前切换的状态
select event_name, work_completed, work_estimated from performance_schema.events_stages_current where event_name LIKE"%stage/group_rpl%";
2.3 切换至单主模式
通过调用函数group_replication_switch_to_single_primary_mode(UUID),可以多主模式切换到单主模式,切换时可以主动指定一个UUID作为主库,如果未指定,则会自动选举出一个主库。选举的规则见:
https://blog.csdn.net/frostlulu/article/details/128629974?spm=1001.2014.3001.5501
切换单主模式,指定slave01为主库:
selectgroup_replication_switch_to_single_primary_mode();
查询切换结果,可以看到slave02的角色为primary,其余为secondary,切换成功:
select* from performance_schema.replication_group_members;
当你从多主模式切换到单主模式时,强一致性检查会自动在所有成员上禁用(group_replication_enforce_update_everywhere_checks=off)
2.4 重启组复制
组复制是为了在部分服务器出现宕机或离线的情况下依然可以提供持续的数据库服务。但有些时候,出于维护需求或事故,需要关闭所有的服务器(所有成员上都执行了stop group_replication)。此时组复制已经名存实亡,想要再次启动时,必须重新引导。
但是重启组复制需要注意,由于各个成员离开或者失败的时间点不同,因此各个成员上的事务可能不同。这里不可以随便选择引导服务器,必须找到具有最大事务集的服务器,由其引导组复制,然后其他成员再加入,通过distributed recovery追赶上主库。
重启步骤:
第1步: 连接到每个成员,如果组复制还未停止,执行stop group_replication停止复制。如果MySQL进程失败了,重启实例,并确认组复制未启动。
第2步:收集所有历史成员的事务集,包含已执行的事务(gtid_executed)和在group_replication_applier的事务(已通过验证还未应用的事务)
select @@global.gtid_executed;
select received_transaction_set
from performance_schema.replication_connection_status
where channel_name="group_replication_applier";
第3步:比较第2步中收集的各个成员的事务集,找出具有最大事务集的服务器的作为主库,并由其引导组复制(创建一个组):
set globalgroup_replication_bootstrap_group=on;
start group_replication;
set globalgroup_replication_bootstrap_group=off;
确认组引导成功:
select* from performance_schema.replication_group_members;
第4步:在所有其他成员上执行start group_replication,使其重新加入组,加入过程:
startgroup_replication;
在任意成员上确认加入成功:
select* from performance_schema.replication_group_members;
三、组复制的限制
组复制通过多台服务器提供具有一定容错功能的持续数据库服务,并提供多主复制、自动故障转移等功能。
但其在使用也有一些限制,例如:
最大成员数量为9个
不支持间隙锁,因此推荐事务使用read-committed隔离级别。
不支持serializable隔离级别(一般也没人用)。
多主模式下select… for update可能导致死锁(锁不会在成员中共享)。
全局复制过滤器不能在组内使用,因为会导致成员处于不一致状态。但是通道过滤器可以使用,
单个事务过大时,可能会导致消息无法及时在各成员间复制(5秒窗口期),成员可能会被怀疑失败并被驱除出组,可以采取下列解决方法:
增大group_replication_member_expel_timeout的值,给事务更多的执行时间(默认5秒)。
从应用角度限制事务的大小
使用变量roup_replication_transaction_size_limit限制事务大小,超过的事务会被回滚,不会发送到组。
使用group_replication_compression_threshold变量限定超过该大小的消息会被压缩(默认1000000bytes,1MB)。
使用group_replication_communication_max_message_size变量设置超过该大小的消息会被分段(默认10485760 bytes,10MB,此变量MySQL8.0.16以上版本可用)。