如果复制由于复制事务中事件出现问题而停止,则可以通过跳过副本上的失败事务来恢复复制。在跳过事务之前,请确保复制 I/O(接收器)线程和 SQL(应用器)线程都已停止。
首先,您需要确定导致错误的复制事件。错误的详细信息以及最后成功应用的事务记录在 Performance Schema 表 replication_applier_status_by_worker
中。您可以使用 mysqlbinlog 检索并显示在错误发生时间附近记录的事件。有关执行此操作的说明,请参见 第 9.5 节,“时间点(增量)恢复”。或者,您可以在副本上发出 SHOW RELAYLOG EVENTS
或在源上发出 SHOW BINLOG EVENTS
。
在跳过事务并重启副本之前,请检查以下几点
停止复制的事务是否来自未知或不可信的来源?如果是,请调查原因,以防存在任何安全问题,表明不应该重启副本。
停止复制的事务是否需要在副本上应用?如果是,请进行相应的更正并重新应用事务,或者手动协调副本上的数据。
停止复制的事务是否需要在源上应用?如果不是,请手动撤消发生事务的服务器上的事务。
要跳过事务,请根据需要选择以下方法之一
使用 GTID 时 (
gtid_mode
为ON
),请参见 第 19.1.7.3.1 节,“使用 GTID 跳过事务”。不使用 GTID 或正在逐步引入 GTID 时 (
gtid_mode
为OFF
、OFF_PERMISSIVE
或ON_PERMISSIVE
),请参见 第 19.1.7.3.2 节,“不使用 GTID 跳过事务”。如果已使用
CHANGE REPLICATION SOURCE TO
语句的ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
选项在复制通道上启用了 GTID 分配,请参见 第 19.1.7.3.2 节,“不使用 GTID 跳过事务”。在复制通道上使用ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
与为通道引入基于 GTID 的复制不同,您不能使用基于 GTID 的复制的那些通道的跳过事务方法。
要重启复制,并在跳过事务后,发出START REPLICA
,如果副本是多源副本,则使用 FOR CHANNEL
子句。
当使用 GTID 时(gtid_mode
为 ON
),即使事务的内容被过滤掉,已提交事务的 GTID 也会保留在副本上。此功能可防止副本在使用 GTID 自动定位重新连接到源时检索之前过滤的事务。它还可以用于跳过副本上的事务,方法是在发生故障的事务位置提交一个空事务。
当您使用 CHANGE REPLICATION SOURCE TO
语句的 ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
选项在复制通道上启用 GTID 分配时,此跳过事务的方法不适用。
如果发生故障的事务在工作线程中生成错误,您可以直接从 Performance Schema 表 replication_applier_status_by_worker
的 APPLYING_TRANSACTION
字段获取其 GTID。要查看事务内容,请在副本上发出 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 的事务已应用。如果副本是多源副本,则提交空事务时不需要指定通道名称,但在发出 START REPLICA
时需要指定通道名称。
请注意,如果此副本正在使用二进制日志记录,则如果副本将来成为源或主服务器,空事务将进入复制流。如果需要避免这种情况,请考虑刷新和清除副本的二进制日志,如以下示例所示
FLUSH LOGS;
PURGE BINARY LOGS TO 'binlog.000146';
空事务的 GTID 会保留,但事务本身会通过清除二进制日志文件而被删除。
要跳过发生故障的事务(当未使用 GTID 或正在逐步引入 GTID 时(gtid_mode
为 OFF
、OFF_PERMISSIVE
或 ON_PERMISSIVE
)),您可以通过发出 SET GLOBAL sql_replica_skip_counter
跳过指定数量的事件。或者,您可以通过发出 CHANGE REPLICATION SOURCE TO
语句向前移动源二进制日志位置来跳过一个或多个事件。
当您使用 CHANGE REPLICATION SOURCE TO
语句的 ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
选项在复制通道上启用 GTID 分配时,这些方法也适用。
当您使用这些方法时,重要的是要理解,您并不一定在跳过完整的事务,就像使用之前描述的基于 GTID 的方法一样。这些基于非 GTID 的方法不知道事务本身,而是对事件进行操作。二进制日志被组织成一系列称为事件组的组,每个事件组都包含一系列事件。
对于事务表,一个事件组对应一个事务。
对于非事务表,一个事件组对应一个 SQL 语句。
虽然单个事务可能包含对事务表和非事务表的更改,但对这类事务的支持已弃用,您应该预期它将在 MySQL 的未来版本中被删除。请参阅 第 19.5.1.36 节,“复制和事务”。有关此弃用的一些原因,请参阅 第 19.1.3.7 节,“使用 GTID 的复制限制”。
当您使用 SET GLOBAL sql_replica_skip_counter
语句跳过事件,并且生成的职位位于事件组的中间时,副本将继续跳过事件,直到到达组的末尾。然后从下一个事件组开始执行。 CHANGE REPLICATION SOURCE TO
语句没有此功能,因此您必须小心识别事件组开头处正确的位置以重新启动复制。但是,使用 CHANGE REPLICATION SOURCE TO
意味着您不必像使用 SET GLOBAL sql_replica_skip_counter
那样计算需要跳过的事件,而只需指定要重新启动的位置。
当您评估了发生故障的事务并执行了先前描述的其他适当操作(例如安全注意事项)后,请计算需要跳过的事件数。一个事件通常对应二进制日志中的一个 SQL 语句,但请注意,使用 AUTO_INCREMENT
或 LAST_INSERT_ID()
的语句在二进制日志中算作两个事件。当使用二进制日志事务压缩时,压缩的事务有效负载 (Transaction_payload_event
) 被计为单个计数器值,因此它内部的所有事件都被视为一个单位跳过。
如果您想跳过完整的事务,您可以计算到事务末尾的事件数,或者您可以跳过相关的事件组。请记住,使用 SET GLOBAL sql_replica_skip_counter
,副本将继续跳过到事件组的末尾。确保您不要跳过得太远,进入下一个事件组或事务,否则它也会被跳过。
请按如下方式发出 SET
语句,其中 N
是要从源中跳过的事件数
SET GLOBAL sql_replica_skip_counter = N
如果设置了 gtid_mode=ON
,或者复制 I/O(接收方)和 SQL(应用方)线程正在运行,则无法发出此语句。
SET GLOBAL sql_replica_skip_counter
语句没有立即生效。当您在发出此 SET
语句后的下一次发出 START REPLICA
语句时,系统变量 sql_replica_skip_counter
的新值将被应用,并且事件将被跳过。该 START REPLICA
语句还会自动将系统变量的值重置为 0。如果副本是多源副本,则在发出该 START REPLICA
语句时,需要使用 FOR CHANNEL
子句。确保您指定了正确的通道名称,否则事件将在错误的通道上被跳过。
当您评估了发生故障的事务并执行了先前描述的其他适当操作(例如安全注意事项)后,请识别源二进制日志中表示合适重新启动复制位置的坐标(文件和位置)。这可能是导致问题事件之后的事件组的开头,或者可能是下一个事务的开头。复制 I/O(接收方)线程在下一次启动时从这些坐标开始从源读取,从而跳过发生故障的事件。确保您已准确识别位置,因为此语句不会考虑事件组。
请按如下方式发出 CHANGE REPLICATION SOURCE TO
语句,其中 source_log_name
是包含重新启动位置的二进制日志文件,而 source_log_pos
是二进制日志文件中表示重新启动位置的数字
CHANGE REPLICATION SOURCE TO SOURCE_LOG_FILE='source_log_name', SOURCE_LOG_POS=source_log_pos;
如果副本是多源副本,则必须在 CHANGE REPLICATION SOURCE TO
语句中使用 FOR CHANNEL
子句来命名相应的通道。
如果 SOURCE_AUTO_POSITION
为 1
,或者复制 I/O(接收方)和 SQL(应用方)线程正在运行,则无法发出此语句。如果需要在 SOURCE_AUTO_POSITION=1
时使用此跳过事务的方法,则可以在发出该语句时将设置更改为 SOURCE_AUTO_POSITION=0
,然后在之后将其更改回。例如
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;