根据您的复制配置,从中继日志执行的事务序列中可能会出现不一致。本节介绍如何避免不一致并解决出现的不一致问题。
可能存在以下类型的不一致
半应用事务。更新非事务性表的某个事务已经应用了一些更改,但并非所有更改都已应用。
间隙。当给定一个排序的事务序列时,序列中后面的某个事务在序列中前面的某个事务之前应用时,就会出现外部化事务集中间隙。间隙仅在使用多线程副本时才会出现。
为了避免在多线程副本上出现间隙,请设置
replica_preserve_commit_order=ON
。这是默认值,因为默认情况下所有副本都是多线程的。在副本上设置
replica_preserve_commit_order=ON
不需要二进制日志记录和副本更新日志记录,如果需要可以禁用它们。设置
replica_preserve_commit_order=ON
需要将replica_parallel_type
设置为LOGICAL_CLOCK
。在 MySQL 8.4 中,这是默认值。在某些特定情况下,如
replica_preserve_commit_order
说明中所列,设置replica_preserve_commit_order=ON
无法在副本上保留提交顺序,因此在这些情况下,在从副本的中继日志执行的事务序列中可能仍然会显示间隙。设置
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
会立即停止。如果正在进行的事务是混合的,STOP REPLICA
会等待最多 60 秒以完成该事务。超时后,它会中止该事务,因此它可能被半完成。
系统变量 rpl_stop_replica_timeout
的全局设置与停止复制线程的过程无关。它只会使发出 STOP REPLICA
的客户端返回到客户端,但复制线程会继续尝试停止。
如果复制通道存在间隙,则它将产生以下后果
副本数据库处于可能从未在源上存在的状态。
Exec_master_log_pos
字段在SHOW REPLICA STATUS
中只是一个 “低水位标记”。换句话说,出现在该位置之前的交易保证已提交,但该位置之后的交易可能已提交或未提交。CHANGE REPLICATION SOURCE TO
该通道的语句会失败并出现错误,除非应用器线程正在运行,并且该语句仅设置接收器选项。如果 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 的复制时,用于解决多线程副本上的间隙的基于二进制日志位置的复制过程完全跳过。跳过此过程时, START REPLICA UNTIL SQL_AFTER_MTS_GAPS
语句的行为有所不同,并且不会尝试检查事务序列中的间隙。您还可以发出 CHANGE REPLICATION SOURCE TO
语句,这些语句在存在间隙的非 GTID 副本上不允许使用。