如果复制由于复制事务中的事件问题而停止,您可以通过跳过副本上失败的事务来恢复复制。在跳过事务之前,确保停止复制 I/O(接收方)线程以及 SQL(应用程序)线程。
首先,您需要确定导致错误的复制事件。错误的详细信息和最后一次成功应用的事务记录在性能模式表中
replication_applier_status_by_worker
。您可以使用mysqlbinlog来检索和显示错误发生前后记录的事件。有关执行此操作的说明,请参阅
第 7.5 节,“时间点(增量)恢复”。或者,您可以SHOW RELAYLOG EVENTS
在副本或SHOW BINLOG EVENTS
源上发布。
在跳过事务并重新启动副本之前,请检查以下几点:
停止从未知或不受信任源复制的事务?如果是这样,请调查原因,以防有任何安全考虑表明不应重新启动副本。
停止复制的事务是否需要应用于副本?如果是这样,要么进行适当的更正并重新应用事务,要么手动协调副本上的数据。
停止复制的事务是否需要在源上应用?如果不是,请在最初发生事务的服务器上手动撤消事务。
要跳过事务,请根据需要选择以下方法之一:
当 GTID 正在使用时(
gtid_mode
是ON
),请参阅 第 17.1.7.3.1 节,“使用 GTID 跳过事务”。当 GTID 未被使用或正在逐步使用时(
gtid_mode
是OFF
,OFF_PERMISSIVE
或ON_PERMISSIVE
),请参阅 第 17.1.7.3.2 节,“跳过没有 GTID 的事务”。如果您使用or语句 的
ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
选项 在复制通道上启用了 GTID 分配 ,请参阅第 17.1.7.3.2 节,“跳过没有 GTID 的事务”。在复制通道上使用 与为该通道引入基于 GTID 的复制不同,您不能对这些通道使用基于 GTID 的复制的事务跳过方法。CHANGE REPLICATION SOURCE TO
CHANGE MASTER TO
ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
要在跳过事务后重新启动复制,请发出
START
REPLICA
带有FOR CHANNEL
如果副本是多源副本的子句的问题。
当 GTID 正在使用时(gtid_mode
是
ON
),即使事务的内容被过滤掉,已提交事务的 GTID 也会保留在副本上。此功能可防止副本在使用 GTID 自动定位重新连接到源时检索先前过滤的事务。它还可以用于跳过副本上的事务,通过提交一个空事务来代替失败的事务。
ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
当您使用语句的选项
在复制通道上启用了 GTID 分配时,这种跳过事务的方法不适用CHANGE REPLICATION SOURCE
TO
。
如果失败的事务在工作线程中产生错误,您可以直接从
APPLYING_TRANSACTION
Performance Schema 表中的字段
获取其 GTID replication_applier_status_by_worker
。要查看事务是什么,请
SHOW RELAYLOG EVENTS
在副本或SHOW BINLOG
EVENTS
源上发出,并在输出中搜索以该 GTID 开头的事务。
当您已评估失败事务以执行前面所述的任何其他适当操作(例如安全考虑)时,要跳过它,请在与失败事务具有相同 GTID 的副本上提交一个空事务。例如:
SET GTID_NEXT='aaa-bbb-ccc-ddd:N';
BEGIN;
COMMIT;
SET GTID_NEXT='AUTOMATIC';
副本上存在此空事务意味着当您发出
START
REPLICA
重新启动复制的语句时,副本使用自动跳过功能忽略失败的事务,因为它看到具有该 GTID 的事务已被应用。如果replica是多源replica,提交空事务的时候不需要指定channel name,但是需要在issue时指定channel name
START
REPLICA
。
请注意,如果此副本正在使用二进制日志记录,则如果副本将来成为源或主副本,则空事务将进入复制流。如果您需要避免这种可能性,请考虑刷新和清除副本的二进制日志,如本例所示:
FLUSH LOGS;
PURGE BINARY LOGS TO 'binlog.000146';
保留空事务的 GTID,但通过清除二进制日志文件删除事务本身。
要在 GTID 未使用或正在分阶段使用(gtid_mode
is
OFF
、OFF_PERMISSIVE
或
)时跳过失败的事务,您可以通过发出一条语句(来自 MySQL 8.0.26)或一条语句ON_PERMISSIVE
来跳过指定数量的事件。或者,您可以通过发出or
语句将源二进制日志位置向前移动
来跳过一个或多个事件
。SET GLOBAL
sql_replica_skip_counter
SET GLOBAL
sql_slave_skip_counter
CHANGE REPLICATION SOURCE TO
CHANGE MASTER TO
当您使用or语句
的ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
选项
在复制通道上启用 GTID 分配时,这些方法也适用
。CHANGE REPLICATION SOURCE
TO
CHANGE MASTER
TO
当您使用这些方法时,重要的是要了解您不一定要跳过一个完整的事务,就像前面描述的基于 GTID 的方法一样。这些非基于 GTID 的方法本身并不知道事务,而是对事件进行操作。二进制日志被组织为一系列称为事件组的组,每个事件组由一系列事件组成。
对于事务表,一个事件组对应一个事务。
对于非事务性表,事件组对应于单个 SQL 语句。
单个事务可以包含对事务和非事务表的更改。
当您使用SET GLOBAL
sql_replica_skip_counter
orSET GLOBAL
sql_slave_skip_counter
语句跳过事件并且结果位置位于事件组的中间时,副本将继续跳过事件,直到它到达组的末尾。然后从下一个事件组开始执行。CHANGE REPLICATION SOURCE
TO
orCHANGE MASTER
TO
语句没有此功能,因此您必须小心识别正确的位置以在事件组的开头重新启动复制。但是,使用
CHANGE REPLICATION SOURCE TO
or
CHANGE MASTER TO
意味着您不必像使用 or 那样计算需要跳过的事件,SET GLOBAL sql_replica_skip_counter
而SET GLOBAL sql_slave_skip_counter
您只需指定重新启动的位置即可。
当您评估了任何其他适当操作(例如安全考虑)的失败事务后,请计算您需要跳过的事件数。一个事件通常对应二进制日志中的一条 SQL 语句,但请注意,在二进制日志中使用AUTO_INCREMENT
或
LAST_INSERT_ID()
计为两个事件的语句。当使用二进制日志事务压缩时,一个压缩的事务负载 ( Transaction_payload_event
) 被算作一个单独的计数器值,所以它里面的所有事件都作为一个单元被跳过。
如果想跳过完整的事务,可以统计到事务结束的事件,也可以直接跳过相关的事件组。请记住,使用
SET GLOBAL sql_replica_skip_counter
或
SET GLOBAL sql_slave_skip_counter
时,副本会继续跳到事件组的末尾。确保您不要跳得太远而进入下一个事件组或事务,以免它也被跳过。
发出SET
如下语句,其中
N
要跳过的来自源的事件数:
SET GLOBAL sql_slave_skip_counter = N
Or from MySQL 8.0.26:
SET GLOBAL sql_replica_skip_counter = N
gtid_mode=ON
如果已设置,或者如果复制 I/O(接收方)和 SQL(应用程序)线程正在运行,则
无法发出此语句
。
SET GLOBAL sql_replica_skip_counter
orSET GLOBAL sql_slave_skip_counter
语句不会立即生效
。当您在该
START
REPLICA
语句之后发出下一次
语句时,将应用系统变量或
SET
的新值
,并跳过事件。该
语句还会自动将系统变量的值设置回 0。如果副本是多源副本,则当您发出该
语句时,该子句是必需的。确保命名正确的频道,否则事件会在错误的频道上被跳过。
sql_replica_skip_counter
sql_slave_skip_counter
START
REPLICA
START
REPLICA
FOR
CHANNEL
当您评估失败的事务以执行前面所述的任何其他适当操作(例如安全考虑)时,请在源的二进制日志中确定坐标(文件和位置),这些坐标代表重新启动复制的合适位置。这可以是导致问题的事件之后的事件组的开始,也可以是下一个事务的开始。复制 I/O(接收方)线程在线程下次启动时开始从这些坐标处的源读取,跳过失败事件。请确保您已准确识别位置,因为此声明未将事件组考虑在内。
发出如下的CHANGE REPLICATION SOURCE
TO
orCHANGE MASTER
TO
语句,其中
source_log_name
是包含重启位置的二进制日志文件,是二进制日志文件中表示重启位置
source_log_pos
的数字:
CHANGE MASTER TO MASTER_LOG_FILE='source_log_name', MASTER_LOG_POS=source_log_pos;
Or from MySQL 8.0.24:
CHANGE REPLICATION SOURCE TO SOURCE_LOG_FILE='source_log_name', SOURCE_LOG_POS=source_log_pos;
如果副本是多源副本,则必须使用
FOR CHANNEL
子句在CHANGE
REPLICATION SOURCE TO
or
CHANGE MASTER TO
语句中命名适当的通道。
SOURCE_AUTO_POSITION=1
如果设置了或
MASTER_AUTO_POSITION=1
,或者如果复制 I/O(接收方)和 SQL(应用程序)线程正在运行,则
无法发出此语句
。SOURCE_AUTO_POSITION=1
如果在正常设置或时需要使用这种跳过事务的方法MASTER_AUTO_POSITION=1
,可以在发出语句时将设置更改为
SOURCE_AUTO_POSITION=0
或
MASTER_AUTO_POSITION=0
,然后再改回。例如:
CHANGE MASTER TO MASTER_AUTO_POSITION=0, MASTER_LOG_FILE='binlog.000145', MASTER_LOG_POS=235;
CHANGE MASTER TO MASTER_AUTO_POSITION=1;
Or from MySQL 8.0.24:
CHANGE REPLICATION SOURCE TO SOURCE_AUTO_POSITION=0, SOURCE_LOG_FILE='binlog.000145', SOURCE_LOG_POS=235;
CHANGE REPLICATION SOURCE TO SOURCE_AUTO_POSITION=1;