19.1.7.3 跳过事务
如果复制因事件在复制事务中出现问题而停止,您可以通过在复制服务器上跳过失败的事务来恢复复制。跳过事务前,请确保复制I/O(接收)线程和SQL(应用)线程都已停止。
首先,您需要确定导致错误的复制事件。错误和最后一次成功应用的事务的详细信息记录在性能chema表replication_applier_status_by_worker
中。您可以使用mysqlbinlog检索和显示在错误发生时的事件。有关如何执行此操作的说明,请参阅第9.5节,“点时(增量)恢复”。Alternatively, you can issueSHOW RELAYLOG EVENTS
on the replica orSHOW BINLOG EVENTS
on the source.
在跳过事务并重新启动复制服务器前,请检查以下点:
-
该事务来自未知或不受信任的源?如果是,调查可能存在的安全考虑,以确定是否应该重新启动复制服务器。
-
该事务需要在复制服务器上应用?如果是,请执行相应的更正和重新应用事务,或者手动在复制服务器上 reconciled数据。
-
该事务需要在源服务器上应用?如果不是,请在源服务器上手动撤销事务。
要跳过事务,请选择以下方法之一:
-
当GTIDs在使用(
gtid_mode
是ON
)时,请参阅第19.1.7.3.1节,“使用GTIDs跳过事务”。 -
当GTIDs不在使用或正在被phased in(
gtid_mode
是OFF
、OFF_PERMISSIVE
或ON_PERMISSIVE
)时,请参阅第19.1.7.3.2节,“不使用GTIDs跳过事务”。 -
如果您已启用了GTID分配在复制通道上,使用
CHANGE REPLICATION SOURCE TO
语句的ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
选项,请参阅第19.1.7.3.2节,“Skipping Transactions Without GTIDs”。使用ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
在复制通道上不是将GTID-based复制引入到通道上,您不能使用事务跳过方法来实现GTID-based复制在那些通道上。
要重新启动复制后跳过事务,请使用START REPLICA
,如果复制是多源复制,请使用FOR CHANNEL
子句。
19.1.7.3.1 跳过事务 With GTIDs
当GTIDs在使用时(gtid_mode
为ON
),GTID为已提交事务的 persisted 在复制器上,即使事务内容被过滤掉。这一特性可以防止复制器在重新连接到源时重新获取之前过滤的事务,也可以用来跳过事务,在跳过事务时,可以提交一个空事务来代替失败的事务。
跳过事务的方法不适用于在使用ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
选项的复制通道上启用GTID分配。
如果失败的事务在工作线程中生成了错误,您可以从APPLYING_TRANSACTION
字段在replication_applier_status_by_worker
表中直接获取其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
语句。
请注意,如果在这个副本上启用二进制日志记录,空事务将进入复制流程,如果副本在将来变为源或主服务器。如果您需要避免这种可能性,请考虑清空和purge副本的二进制日志文件,如下所示:
FLUSH LOGS;
PURGE BINARY LOGS TO 'binlog.000146';
空事务的GTID被持久保存,但是事务本身被purge二进制日志文件中。
19.1.7.3.2 跳过事务 Without GTIDs
在GTIDs不可用或正在被phased in(gtid_mode
为OFF
、OFF_PERMISSIVE
或ON_PERMISSIVE
)时,您可以使用SET GLOBAL sql_replica_skip_counter
来跳过指定的事件 Alternatively,您可以使用CHANGE REPLICATION SOURCE TO
语句将源二进制日志位置向前移动。
这些方法也适用于在复制通道上启用GTID分配使用ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
选项的CHANGE REPLICATION SOURCE TO
语句。
当使用这些方法时,请注意,您并不是一定跳过完整的事务,而是跳过事件。这些非GTID方法不知道事务,而是操作事件。二进制日志是以事件组为单位组织的,每个事件组由一系列事件组成。
-
对于事务表,事件组对应于事务。
-
对于非事务表,事件组对应于单个SQL语句。
单个事务可以包含对事务和非事务表的更改。
当您使用 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
,复制服务器将继续跳过到事件组的结尾。确保您没有跳过太远,进入下一个事件组或事务。
使用以下语句,where N
是从源跳过的事件数量:
SET GLOBAL sql_replica_skip_counter = N
这个语句不能在 gtid_mode=ON
设置的情况下或在复制 I/O(receiver)和 SQL(applier)线程运行的情况下被issued。
SET GLOBAL sql_replica_skip_counter语句没有立即效果。当你下次执行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;
如果是多源复制,必须使用FOR CHANNEL
子句在CHANGE REPLICATION SOURCE TO
语句中指定适当的通道名称。
该语句不能在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;