根据您的复制配置,从中继日志执行的事务序列可能会出现不一致。本节说明如何避免不一致并解决它们引起的任何问题。
可能存在以下类型的不一致:
半应用事务。更新非事务表的事务应用了部分但不是全部更改。
差距。当给定一个有序的交易序列时,当在序列中较晚的交易在序列中较早的其他交易之前应用时,外部化交易集中就会出现间隙。只有在使用多线程副本时才会出现间隙。
为避免在多线程副本上出现间隙,请设置
replica_preserve_commit_order=ON
(从 MySQL 8.0.26 开始)或slave_preserve_commit_order=ON
(在 MySQL 8.0.26 之前)。从 MySQL 8.0.27 开始,此设置为默认设置,因为从该版本开始,所有副本默认都是多线程的。直到并包括 MySQL 8.0.18,保留提交顺序需要同时启用二进制日志记录 (
log_bin
) 和副本更新日志记录 (log_replica_updates
或log_slave_updates
),这是 MySQL 8.0 的默认设置。从 MySQL 8.0.19 开始,副本上不需要二进制日志记录和副本更新日志记录来设置replica_preserve_commit_order=ON
或slave_preserve_commit_order=ON
,如果需要可以禁用。在所有版本中,设置
replica_preserve_commit_order=ON
或slave_preserve_commit_order=ON
要求replica_parallel_type
(从 MySQL 8.0.26 开始)或slave_parallel_type
(在 MySQL 8.0.26 之前)设置为LOGICAL_CLOCK
. 从 MySQL 8.0.27(但不是早期版本)开始,这是默认设置。在某些特定情况下,如 和 的描述中所列
replica_preserve_commit_order
,slave_preserve_commit_order
设置replica_preserve_commit_order=ON
或slave_preserve_commit_order=ON
不能保留副本上的提交顺序,因此在这些情况下,从副本的中继日志执行的事务序列中可能仍会出现间隙。设置
replica_preserve_commit_order=ON
或slave_preserve_commit_order=ON
不防止源二进制日志位置滞后。源二进制日志位置滞后。即使没有差距,也有可能
Exec_master_log_pos
应用了之后的交易。也就是说,到 point 为止的所有交易N
都已应用,并且没有应用之后的交易N
,但Exec_master_log_pos
其值小于N
。在这种情况下,Exec_master_log_pos
是申请的交易的“低水位线”,落后于最近申请的交易的位置。这只会发生在多线程副本上。启用replica_preserve_commit_order
或slave_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
(从 MySQL 8.0.26 开始)或
rpl_stop_slave_timeout
(在 MySQL 8.0.26 之前)与停止复制线程的过程无关。它只会使发出问题的客户端
STOP
REPLICA
返回到客户端,但复制线程会继续尝试停止。
如果复制通道存在间隙,则会产生以下后果:
副本数据库处于源上可能从未存在过的状态。
Exec_master_log_pos
中 的字段SHOW REPLICA STATUS
只是一个“低水位线”。换句话说,保证在该位置之前出现的事务已提交,但在该位置之后的事务可能已提交或未提交。CHANGE REPLICATION SOURCE TO
并且CHANGE MASTER TO
该通道的语句失败并出现错误,除非应用程序线程正在运行并且该语句仅设置接收器选项。如果mysqld以 启动
--relay-log-recovery
,则不会对该通道进行任何恢复,并打印一条警告。如果mysqldump与
--dump-replica
or 一起使用--dump-slave
,它不会记录间隙的存在;因此它打印CHANGE REPLICATION SOURCE TO
|CHANGE MASTER TO
withRELAY_LOG_POS
设置为 中的“低水位线”位置Exec_master_log_pos
。在另一台服务器上应用转储并启动复制线程后,再次复制该位置之后出现的事务。请注意,如果启用了 GTID,这是无害的(但是,在这种情况下,不建议使用
--dump-replica
or--dump-slave
)。
如果复制通道有源二进制日志位置滞后但没有间隙,则上述情况 2 到 5 适用,但情况 1 不适用。
源二进制日志位置信息以二进制格式保存在内表中
mysql.slave_worker_info
。
START REPLICA
[SQL_THREAD]
始终查阅此信息,以便它仅应用正确的交易。即使replica_parallel_workers
or
slave_parallel_workers
之前已更改为 0
START
REPLICA
,并且即使 if
START
REPLICA
与UNTIL
子句一起使用,这仍然是正确的。
START REPLICA
UNTIL SQL_AFTER_MTS_GAPS
仅应用所需数量的交易以填补空白。If
START
REPLICA
与UNTIL
告诉它在消耗完所有间隙之前停止的子句一起使用,然后它会留下剩余的间隙。
RESET
REPLICA
删除中继日志并重置复制位置。因此
RESET
REPLICA
,在具有间隙的多线程副本上发布意味着副本会丢失有关间隙的任何信息,而不会更正间隙。在这种情况下,如果正在使用基于二进制日志位置的复制,则恢复过程会失败。
当基于 GTID 的复制正在使用 ( GTID_MODE=ON
) 并
SOURCE_AUTO_POSITION
使用语句为复制通道设置CHANGE
REPLICATION SOURCE TO
时,恢复过程不需要旧的中继日志。相反,副本可以使用 GTID 自动定位来计算与源相比它缺少的事务。从 MySQL 8.0.26 开始,当使用基于 GTID 的复制时,用于解决多线程副本上的间隙的基于二进制日志位置的复制的过程被完全跳过。跳过该过程时,
START REPLICA
UNTIL SQL_AFTER_MTS_GAPS
语句的行为会有所不同,并且不会尝试检查事务序列中的间隙。你也可以发出
CHANGE REPLICATION SOURCE TO
语句,在存在间隙的非 GTID 副本上是不允许的。