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