16.1.7.3 跳过 Transaction

如果由于复制事务中的事件问题而导致复制停止,则可以通过跳过副本上失败的事务来恢复复制。跳过事务之前,请确保复制 I/O 线程以及复制 SQL 线程已停止。

首先,您需要确定导致错误的复制事件。错误的详细信息和上一次成功应用的事务的详细信息记录在性能模式 tablereplication_applier_status_by_worker中。您可以使用mysqlbinlog来检索和显示错误发生前后记录的事件。有关执行此操作的说明,请参见第 7.5 节“时间点(增量)恢复”。或者,您可以在副本上发出显示中继事件或在源上发出显示 BINLOG 事件

在跳过事务并重新启动副本之前,请检查以下几点:

  • 事务是否停止了来自未知或不受信任来源的复制?如果是这样,请调查原因,以防万一有任何安全注意事项指示不应重新启动副本。

  • 是否需要将停止复制的事务应用于副本?如果是这样,请进行适当的更正并重新应用事务,或手动协调副本上的数据。

  • 停止复制的事务是否需要在源上应用?如果不是,请在最初发生事务的服务器上手动撤消该事务。

要跳过该事务,请选择以下方法之一:

要在跳过事务之后重新启动复制,如果副本是多源副本,请使用FOR CHANNEL子句发出START SLAVE

16.1.7.3.1 使用 GTID 跳过事务

使用 GTID 时(gtid_modeON),即使已过滤掉事务的内容,提交事务的 GTID 也会保留在副本上。当副本使用 GTID 自动定位重新连接到源时,此功能可防止副本检索以前过滤的事务。通过提交空事务代替失败的事务,它也可以用于跳过副本上的事务。

如果失败的事务在工作线程中生成错误,则可以直接从“性能模式”tablereplication_applier_status_by_workerLAST_SEEN_TRANSACTION字段中获取其 GTID。若要查看事务是什么,请在副本上发出显示中继事件或在源上发出显示 BINLOG 事件,然后在输出中搜索该 GTID 之前的事务。

当您评估了失败的事务是否有上述任何其他适当的操作(例如安全性考虑)后,要跳过该事务,请对具有与失败的事务相同的 GTID 的副本提交一个空事务。例如:

SET GTID_NEXT='aaa-bbb-ccc-ddd:N';
BEGIN;
COMMIT;
SET GTID_NEXT='AUTOMATIC';

副本上存在此空事务意味着,当您发出START SLAVE语句重新启动复制时,副本将使用自动跳过功能忽略失败的事务,因为它会看到已应用了具有该 GTID 的事务。如果副本是多源副本,则在提交空事务时不需要指定通道名称,但是在发出START SLAVE时确实需要指定通道名称。

请注意,如果此副本上正在使用二进制日志记录,则如果该副本将来成为源或主副本,则空事务将进入复制流。如果需要避免这种可能性,请考虑刷新和清除副本的二进制日志,如以下示例所示:

FLUSH LOGS;
PURGE BINARY LOGS TO 'binlog.000146';

空事务的 GTID 会保留,但是通过清除二进制日志文件会删除事务本身。

16.1.7.3.2 不使用 GTID 跳过 Transaction

要在不使用 GTID 或不使用 GTID 的情况下跳过失败的事务(gtid_modeOFFOFF_PERMISSIVEON_PERMISSIVE),则可以通过发出SET GLOBAL sql_slave_skip_counter语句来跳过指定数量的事件。或者,您可以通过发出更改为主语句跳过源事件,从而向前跳过源的二进制日志位置。

当您使用这些方法时,重要的是要了解到您不一定要跳过一个完整的事务,就像前面介绍的基于 GTID 的方法一样。这些基于非 GTID 的方法不知道事务本身,而是对事件进行操作。二进制日志被组织为一组称为事件组的序列,每个事件组均由一系列事件组成。

  • 对于事务 table,事件组对应于一个事务。

  • 对于非事务处理 table,事件组对应于一个 SQL 语句。

单个事务可以包含对事务 table 和非事务 table 的更改。

当您使用SET GLOBAL sql_slave_skip_counter语句跳过事件并且结果位置位于事件组的中间时,副本将 continue 跳过事件,直到到达组末尾为止。然后从下一个事件组开始执行。 更改为主语句不具有此功能,因此您必须小心标识正确的位置,以便在事件组的开头重新启动复制。但是,使用更改为主意味着您不必像SET GLOBAL sql_slave_skip_counter一样对需要跳过的事件进行计数,而只需指定要重新启动的位置即可。

16.1.7.3.2.1 使用 SET GLOBAL sql_slave_skip_counter 跳过事务

当您评估了失败的事务是否有其他任何如上所述的适当操作(例如,安全考虑)后,请计算需要跳过的事件数。一个事件通常对应于二进制日志中的一个 SQL 语句,但请注意,使用AUTO_INCREMENTLAST_INSERT_ID()的语句在二进制日志中计为两个事件。使用二进制日志事务压缩时,将压缩的事务有效负载(Transaction_payload_event)计为单个计数器值,因此将跳过其中的所有事件作为一个单元。

如果要跳过完整的事务,则可以将事件计数到事务结束,或者可以跳过相关的事件组。请记住,使用SET GLOBAL sql_slave_skip_counter,副本将 continue 跳至事件组的末尾。确保不要跳过太远而进入下一个事件组或事务,因为这也会被跳过。

发出如下的SET语句,其中* N *是源中要跳过的事件数:

SET GLOBAL sql_slave_skip_counter = N

如果设置了gtid_mode=ON或副本线程正在运行,则无法发出此语句。

SET GLOBAL sql_slave_skip_counter语句没有立即生效。当您在此SET语句之后下一次发出START SLAVE语句时,将应用系统变量sql_slave_skip_counter的新值,并跳过事件。该START SLAVE语句还将自动将系统变量的值设置回 0.如果该副本是多源副本,则在发出该START SLAVE语句时,需要FOR CHANNEL子句。确保您命名了正确的 Channels,否则事件将在错误的 Channels 上被跳过。

16.1.7.3.2.2 使用 CHANGE MASTER TO 跳过事务

在评估了失败的事务是否有上述任何其他适当操作(例如安全性考虑)后,请在源二进制日志中标识代 table 重新启动复制的适当位置的坐标(文件和位置)。这可以是导致问题的事件之后的事件组的开始,也可以是下一个事务的开始。复制 I/O 线程将在线程下次启动时从这些坐标处的源开始读取,从而跳过失败的事件。确保您已正确确定位置,因为该语句未考虑事件组。

发出如下的更改为主语句,其中* source_log_name 是包含重新启动位置的二进制日志文件, source_log_pos *是代 table 二进制日志文件中所述的重新启动位置的数字:

CHANGE MASTER TO MASTER_LOG_FILE='source_log_name', MASTER_LOG_POS=source_log_pos;

如果副本是多源副本,则必须使用FOR CHANNEL子句在更改为主语句上命名适当的通道。

如果设置了MASTER_AUTO_POSITION=1或复制线程正在运行,则不能发出此语句。如果通常设置MASTER_AUTO_POSITION=1时需要使用这种跳过事务的方法,则可以在发出语句时将设置更改为MASTER_AUTO_POSITION=1,然后再将其更改回。例如:

CHANGE MASTER TO MASTER_AUTO_POSITION=0, MASTER_LOG_FILE='binlog.000145', MASTER_LOG_POS=235;
CHANGE MASTER TO MASTER_AUTO_POSITION=1;