19.5.1.34 复制和事务不一致
根据您的复制配置,可能会出现事务顺序不一致的问题。这一节解释了如何避免这些问题和解决它们引起的问题。
可能存在以下类型的不一致:
-
部分应用的事务。一个更新非事务表的事务已经应用了一部分,但不是所有的变化。
-
空隙。在一个有序的事务序列中,一个在序列中的事务被应用于在其他事务之前的位置。这只能在使用多线程复制时出现。
要避免在多线程复制中出现空隙,设置
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=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
。这确保了它从不留下空隙或源二进制日志位置滞后,除非上述情况之一 Applies,即在STOP REPLICA
完成前,出现错误,或者另一个线程发出KILL
,或者服务器重新启动。在这些情况下,STOP REPLICA
将成功返回。 -
如果最后一个事务在relay日志中只被部分接收,并且多线程复制的协调线程已经开始将事务分配给工作者,那么
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
语句对该渠道失败,除非applier线程正在运行且语句只设置接收器选项。 -
如果mysqld以
--relay-log-recovery
启动,不执行该渠道的恢复,并打印警告。 -
如果使用mysqldump工具
--dump-replica
,它不会记录空隙的存在;因此,它将打印CHANGE REPLICATION SOURCE TO
,并将RELAY_LOG_POS
设置为“低水位标记”的位置在Exec_master_log_pos
中。在将备份应用于另一个服务器,并启动复制线程后,位于该位置后的交易将再次被复制。请注意,这在GTIDs启用时是安全的(然而,在这种情况下,不建议使用
--dump-replica
)。
如果复制渠道存在源二进制日志位置延迟但无空隙,情况2-5将适用,但情况1不适用。
源二进制日志位置信息将以二进制格式在内部表mysql.slave_worker_info
中持久化。START REPLICA [SQL_THREAD]
总是咨询这个信息,以便只应用正确的交易。这在replica_parallel_workers
被更改为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复制器上不允许存在空隙。