根据您的复制配置,relay日志中执行的事务序列可能会出现不一致。 本节解释如何避免不一致和解决它们引起的问题。
以下类型的不一致可能存在:
-
半应用事务。一个更新非事务表的事务已经应用了一些但不是所有的更改。
-
间隙。在外部事务集序列中,一个事务在序列中较晚出现,但在序列中较早出现的某个事务之前应用。间隙只能在多线程副本上出现。
要避免多线程副本上的间隙,设置
replica_preserve_commit_order=ON
。这是默认值,因为所有副本默认都是多线程的。在副本上不需要二进制日志记录和副本更新日志记录来设置
replica_preserve_commit_order=ON
,可以禁用它们。设置
replica_preserve_commit_order=ON
需要replica_parallel_type
设置为LOGICAL_CLOCK
。在 MySQL 8.3 中,这是默认值。在某些特定情况下,如
replica_preserve_commit_order
的描述中所列举的那样,设置replica_preserve_commit_order=ON
不能在副本上保留提交顺序,因此在这些情况下,relay日志中执行的事务序列可能仍然出现间隙。设置
replica_preserve_commit_order=ON
不会防止源二进制日志位置滞后。 -
源二进制日志位置滞后。即使没有间隙,也可能出现事务在
Exec_master_log_pos
之后被应用的情况。也就是说,所有事务直到点N
都被应用,而没有事务在N
之后被应用,但是Exec_master_log_pos
的值小于N
。在这种情况下,Exec_master_log_pos
是事务应用的“低水位标记”,并且落后于最新应用事务的位置。这只能在多线程副本上出现。启用replica_preserve_commit_order
不会防止源二进制日志位置滞后。
以下场景与半应用事务、间隙和源二进制日志位置滞后相关:
-
当复制线程正在运行时,可能会出现间隙和半应用事务。
-
mysqld 关闭。无论是干净关闭还是不干净关闭,都会中止正在进行的事务,可能留下间隙和半应用事务。
-
KILL
复制线程(单线程副本的 SQL 线程或多线程副本的协调器线程)。这将中止正在进行的事务,可能留下间隙和半应用事务。 -
应用程序线程中的错误。这可能留下间隙。如果错误发生在混合事务中,那么该事务将半应用。当使用多线程副本时,未收到错误的工作者将完成队列,因此可能需要一些时间来停止所有线程。
-
STOP REPLICA
在使用多线程副本时。当发出STOP REPLICA
后,副本等待任何差距被填充,然后更新Exec_master_log_pos
。这确保它从不留下差距或源二进制日志位置滞后,除非出现上述情况,即在STOP REPLICA
完成之前,出现错误,或者另一个线程发出KILL
,或者服务器重新启动。在这些情况下,STOP REPLICA
返回成功。 -
如果最后一个事务在中继日志中只接收了一半,并且多线程副本的协调器线程已经开始安排事务到工作者,那么
STOP REPLICA
等待最多 60 秒以接收事务。超时后,协调器放弃并中止事务。如果事务是混合的,它可能留下不完整。 -
如果正在进行的事务仅更新事务表,那么
STOP REPLICA
立即停止。如果正在进行的事务是混合的,STOP REPLICA
等待最多 60 秒以完成事务。超时后,它中止事务,因此可能留下不完整。
系统变量 rpl_stop_replica_timeout
的全局设置与停止复制线程的过程无关。它只是使客户端发出 STOP REPLICA
返回客户端,但复制线程继续尝试停止。
如果复制通道存在差距,将产生以下后果:
-
副本数据库处于可能从不曾存在于源的状态。
-
字段
Exec_master_log_pos
在SHOW REPLICA STATUS
中只是一个“低水位标记”。换言之,在该位置之前的交易已经提交,但该位置之后的交易可能已经提交或尚未提交。 -
CHANGE REPLICATION SOURCE TO
语句对于该通道将失败,除非 applier 线程正在运行,并且语句仅设置接收器选项。 -
如果 mysqld 使用
--relay-log-recovery
启动,则不会对该通道进行恢复,并打印警告。 -
如果 mysqldump 使用
--dump-replica
,它不会记录差距的存在;因此,它将打印CHANGE REPLICATION SOURCE TO
语句,RELAY_LOG_POS 设置为Exec_master_log_pos
中的“低水位标记”位置。在另一个服务器上应用转储,并启动复制线程后,位置之后的交易将被复制。注意,这是无害的,如果启用了 GTID(但是,在这种情况下,不建议使用
--dump-replica
)。
如果复制通道存在源二进制日志位置滞后,但没有差距,则情况 2 到 5 以上适用,但情况 1 不适用。
二进制日志位置信息以二进制格式持久化在内部表 mysql.slave_worker_info
中。START REPLICA [SQL_THREAD]
总是咨询该信息,以便仅应用正确的事务。这仍然是正确的,即使 replica_parallel_workers
在 START REPLICA
之前被更改为 0,并且即使 START REPLICA
与 UNTIL
一起使用。START REPLICA UNTIL SQL_AFTER_MTS_GAPS
只应用足够的事务以填充间隙。如果 START REPLICA
与 UNTIL
子句一起使用,以便停止在所有间隙之前,那么它将留下剩余的间隙。
RESET REPLICA
删除中继日志并重置复制位置。因此,在多线程副本上发出 RESET REPLICA
,意味着副本将失去关于间隙的所有信息,而不纠正间隙。在这种情况下,如果使用基于二进制日志位置的复制,那么恢复过程将失败。
当使用基于 GTID 的复制 (GTID_MODE=ON
) 并且使用 CHANGE REPLICATION SOURCE TO
语句为复制通道设置 SOURCE_AUTO_POSITION
时,旧的中继日志不再需要用于恢复过程。相反,副本可以使用 GTID 自动定位来计算它相比源缺少的交易。基于二进制日志位置的复制来解决多线程副本上的间隙的过程将被跳过,而 GTID-based 复制正在使用。当该过程被跳过时,START REPLICA UNTIL SQL_AFTER_MTS_GAPS
语句的行为将不同,不会尝试检查交易序列中的间隙。你也可以发出 CHANGE REPLICATION SOURCE TO
语句,这些语句在非 GTID 副本上不允许存在间隙时不允许使用。