虽然 事务同步点 部分解释了从概念上讲,您可以选择两个同步点:读或写,这些术语是简化了的,组复制中使用的术语是:之前 和 之后 事务执行。一致性级别对组处理的只读 (RO) 和读写 (RW) 事务可能产生不同的影响,如本节所示。
以下列表显示了您可以在组复制中使用 group_replication_consistency
变量配置的可能一致性级别,按事务一致性保证的程度递增排序
EVENTUAL
RO 和 RW 事务都不会等待先前的事务应用完成,然后才执行。这是在添加
group_replication_consistency
变量之前组复制的行为。RW 事务不会等待其他成员应用事务。这意味着事务可能在一个成员上外部化,而其他成员尚未外部化。这也意味着,如果发生主服务器故障转移,新主服务器可以在之前的主服务器上的所有事务都应用之前接受新的 RO 和 RW 事务。RO 事务可能导致过时值,RW 事务可能由于冲突而导致回滚。BEFORE_ON_PRIMARY_FAILOVER
新的 RO 或 RW 事务将被一个新当选的主服务器保留(不应用),该主服务器正在应用来自旧主服务器的积压,直到任何积压都应用完成。这确保了当主服务器故障转移发生时(无论有意还是无意),客户端始终在主服务器上看到最新的值。这保证了一致性,但意味着客户端必须能够处理在应用积压时发生的延迟。通常,这种延迟应该很小,但它确实取决于积压的大小。
BEFORE
RW 事务在被应用之前等待所有先前的事务完成。RO 事务在执行之前等待所有先前的事务完成。这确保了该事务仅通过影响事务的延迟来读取最新值。这通过确保仅在 RO 事务上使用同步来减少每次 RW 事务的同步开销。这种一致性级别还包括由
BEFORE_ON_PRIMARY_FAILOVER
提供的一致性保证。AFTER
RW 事务等待其更改应用到所有其他成员。此值对 RO 事务没有影响。此模式确保当事务在本地成员上提交时,任何后续事务在任何组成员上读取写入的值或更近的值。将此模式与主要用于 RO 操作的组一起使用,以确保应用的 RW 事务一旦提交就会应用到任何地方。您的应用程序可以使用此模式来确保后续读取获取包含最新写入的最新数据。这通过确保仅在 RW 事务上使用同步来减少每次 RO 事务的同步开销。这种一致性级别还包括由
BEFORE_ON_PRIMARY_FAILOVER
提供的一致性保证。BEFORE_AND_AFTER
RW 事务等待 1) 所有先前的事务完成,然后才被应用,2) 直到其更改应用到其他成员。RO 事务在执行之前等待所有先前的事务完成。这种一致性级别还包括由
BEFORE_ON_PRIMARY_FAILOVER
提供的一致性保证。
BEFORE
和 BEFORE_AND_AFTER
一致性级别都可以在 RO 和 RW 事务上使用。 AFTER
一致性级别对 RO 事务没有影响,因为它们不会生成更改。
不同的一致性级别为 DBA 提供了灵活性,DBA 可以使用它们来设置基础设施;也为开发人员提供了灵活性,开发人员可以使用最适合其应用程序需求的一致性级别。以下场景显示了如何根据您使用组的方式选择一致性保证级别
场景 1 您希望对读取进行负载均衡,而不必担心陈旧读取,组写入操作远少于组读取操作。在这种情况下,您应该选择
AFTER
。场景 2 您有一个数据集,该数据集执行大量写入,并且您希望偶尔执行读取,而不必担心读取陈旧数据。在这种情况下,您应该选择
BEFORE
。场景 3 您希望工作负载中的特定事务始终从组中读取最新数据,因此每当敏感数据更新时(例如,文件的凭据或类似数据),您希望强制执行读取始终读取最新的值。在这种情况下,您应该选择
BEFORE
。场景 4 您有一个组,该组主要包含只读 (RO) 数据,您希望读写 (RW) 事务在提交后应用到任何地方,以便后续读取在包含最新写入的最新数据上完成,并且您不希望在每个 RO 事务上支付同步费用,而只在 RW 事务上支付同步费用。在这种情况下,您应该选择
AFTER
。场景 5 假设你有一个主要包含只读数据的组,你希望你的读写 (RW) 事务始终从该组读取最新数据,并在提交后应用到所有地方,以便后续读取操作都使用包含最新写入的最新数据,并且你不会为每个只读 (RO) 事务支付同步成本,而只为 RW 事务支付同步成本。在这种情况下,你应该选择
BEFORE_AND_AFTER
。
你可以自由选择一致性级别强制执行的范围。这很重要,因为如果在全局范围内设置一致性级别,它可能会对组性能产生负面影响。因此,你可以使用 group_replication_consistency
系统变量在不同范围内配置组的一致性级别。
要在当前会话上强制执行一致性级别,请使用会话范围
> SET @@SESSION.group_replication_consistency= 'BEFORE';
要在所有会话上强制执行一致性级别,请使用全局范围
> SET @@GLOBAL.group_replication_consistency= 'BEFORE';
能够在特定会话上设置一致性级别使你能够利用以下场景:
场景 6 给定系统处理多个不需要强一致性级别的指令,但有一种指令需要强一致性:管理对文档的访问权限。在这种情况下,系统更改访问权限,它希望确保所有客户端都看到正确的权限。你只需要在这些指令上执行
SET @@SESSION.group_replication_consistency= ‘AFTER’
,并将其他指令保留在全局范围内设置的EVENTUAL
下运行。场景 7 与场景 6 中描述的相同系统,每天有一条指令需要进行一些分析处理,因此它需要始终读取最新数据。为了实现这一点,你只需要在该特定指令上执行
SET @@SESSION.group_replication_consistency= ‘BEFORE’
。
总之,你不需要以特定的一致性级别运行所有事务,尤其是在只有某些事务实际需要它的时候。
请注意,所有读写事务在组复制中都是完全排序的,因此即使你将当前会话的一致性级别设置为 AFTER
,此事务也会等待,直到它的更改应用于所有成员,这意味着等待此事务和所有可能在从库队列中的先前事务。实际上,一致性级别 AFTER
会等到包括此事务在内的所有事务都完成。
另一种对一致性级别进行分类的方法是根据它们对组的影响,也就是说,一致性级别对其他成员产生的影响。
除了在事务流中排序之外,BEFORE
一致性级别只影响本地成员。也就是说,它不需要与其他成员协调,也不需要对它们的事务产生影响。换句话说,BEFORE
仅影响使用它的事务。
AFTER
和 BEFORE_AND_AFTER
一致性级别确实会对其他成员上执行的并发事务产生副作用。这些一致性级别会导致其他成员的事务等待,如果具有 EVENTUAL
一致性级别的事务在具有 AFTER
或 BEFORE_AND_AFTER
的事务正在执行时开始。其他成员会等到 AFTER
事务在该成员上提交,即使其他成员的事务具有 EVENTUAL
一致性级别。换句话说,AFTER
和 BEFORE_AND_AFTER
会影响 所有 ONLINE
组成员。
为了进一步说明这一点,想象一个包含 3 个成员 M1、M2 和 M3 的组。在成员 M1 上,客户端发出以下指令:
> SET @@SESSION.group_replication_consistency= AFTER;
> BEGIN;
> INSERT INTO t1 VALUES (1);
> COMMIT;
然后,在上述事务正在应用时,在成员 M2 上,客户端发出以下指令:
> SET SESSION group_replication_consistency= EVENTUAL;
在这种情况下,即使第二个事务的一致性级别是 EVENTUAL
,因为它在第一个事务已经进入提交阶段时开始执行,因此第二个事务必须等待第一个事务完成提交,然后才能执行。
你只能在 ONLINE
成员上使用一致性级别 BEFORE
、AFTER
和 BEFORE_AND_AFTER
,尝试在其他状态的成员上使用它们会导致会话错误。
一致性级别不是 EVENTUAL
的事务会一直保持执行状态,直到达到由 wait_timeout
值配置的超时时间,该值默认为 8 小时。如果达到超时时间,则会抛出 ER_GR_HOLD_WAIT_TIMEOUT
错误。
本节介绍组的一致性级别如何影响已选举出新主库的单主库组。此类组会自动检测故障并调整活动成员的视图,换句话说,就是成员资格配置。此外,如果组以单主库模式部署,无论何时组的成员资格发生变化,都会进行检查以检测组中是否仍然存在主库成员。如果没有,则会从从库成员列表中选择一个新的主库。通常,这被称为从库提升。
鉴于系统会自动检测故障并重新配置自身,用户也可能期望一旦提升完成,新的主库就处于与旧主库完全相同的数据状态。换句话说,用户可能期望在新的主库能够从中读取和写入数据后,不会有已复制事务的积压工作需要应用到该新的主库。从实际角度来看,用户可能期望一旦他的应用程序故障转移到新的主库,即使是暂时性地,也不会有读取旧数据或写入旧数据记录的机会。
当在组上激活并正确调整流量控制时,在提升后立即从新选出的主库中暂时读取陈旧数据的可能性很小,因为不应该存在积压工作,或者如果存在,积压工作应该很小。此外,你可能拥有一个代理或中间件层来管理应用程序在提升后对主库的访问,并在该级别强制执行一致性标准。你可以使用 group_replication_consistency
变量来指定新主库在提升后 的行为方式,该变量控制是否在新主库完全应用积压工作之前阻止读取和写入操作。如果 group_replication_consistency
变量设置为 BEFORE_ON_PRIMARY_FAILOVER
,在新选出的主库上存在要应用的积压工作,并且在该新的主库仍在应用积压工作时向其发出事务,则传入事务将被阻止,直到积压工作完全应用。因此,将防止以下异常情况:
对只读和读写事务没有陈旧读取。这可以防止新的主库将陈旧读取外部化为应用程序。
由于仍在积压工作中等待应用的已复制读写事务而导致的读写冲突,对读写事务没有虚假回滚。
对读写事务没有读取偏差,例如:
> BEGIN; > SELECT x FROM t1; -- x=1 because x=2 is in the backlog; > INSERT x INTO t2; > COMMIT;
此查询不应导致冲突,但会写入过时的值。
总之,当 group_replication_consistency
设置为 BEFORE_ON_PRIMARY_FAILOVER
时,你选择优先考虑一致性而不是可用性,因为无论何时选举出新的主库,读取和写入都会被阻止。这是在配置组时需要考虑的权衡。还应该记住,如果流量控制工作正常,积压工作应该很小。请注意,更高级的一致性级别 BEFORE
、AFTER
和 BEFORE_AND_AFTER
还包括 BEFORE_ON_PRIMARY_FAILOVER
提供的一致性保证。
为了保证组提供相同的一致性级别,无论哪个成员被提升为主库,组的所有成员都应该将其 BEFORE_ON_PRIMARY_FAILOVER
(或更高的一致性级别)持久化到其配置中。例如,在每个成员上发出以下指令:
> SET PERSIST group_replication_consistency='BEFORE_ON_PRIMARY_FAILOVER';
这确保了所有成员的行为方式都相同,并且在成员重新启动后,配置将被持久化。
事务不能无限期地处于挂起状态,如果挂起时间超过 wait_timeout
,则会返回 ER_GR_HOLD_WAIT_TIMEOUT 错误。
虽然在使用 BEFORE_ON_PRIMARY_FAILOVER
一致性级别时所有写入都会被阻止,但并非所有读取都会被阻止,以确保你仍然可以在提升后服务器应用积压工作时检查服务器。这对调试、监控、可观测性和故障排除很有用。一些不会修改数据的查询是允许的,例如以下内容:
允许的 SHOW
语句是 SHOW VARIABLES
、SHOW PROCESSLIST
、SHOW STATUS
、SHOW ENGINE INNODB LOGS
、SHOW ENGINE INNODB STATUS
、SHOW ENGINE INNODB MUTEX
、SHOW BINARY LOG STATUS
、SHOW REPLICA STATUS
、SHOW CHARACTER SET
、SHOW COLLATION
、SHOW BINARY LOGS
、SHOW OPEN TABLES
、SHOW REPLICAS
、SHOW BINLOG EVENTS
、SHOW WARNINGS
、SHOW ERRORS
、SHOW ENGINES
、SHOW PRIVILEGES
、SHOW PROCEDURE STATUS
、SHOW FUNCTION STATUS
、SHOW PLUGINS
、SHOW EVENTS
、SHOW PROFILE
、SHOW PROFILES
和 SHOW RELAYLOG EVENTS
。