### 17.4.2 处理副本的意外停止

[](<>)[](<>)[](<>)

为了使复制对服务器的意外停止具有弹性（有时被描述为崩溃安全），副本必须能够在停止之前恢复其状态。本节介绍复制期间副本意外停止的影响，以及如何配置副本以获得最佳恢复机会以继续复制。

在副本意外停止后，重新启动复制 SQL 线程必须恢复有关已执行哪些事务的信息。恢复所需的信息存储在副本的应用程序元数据存储库中。从 MySQL 8.0 开始，此存储库默认创建为[`InnoDB`](innodb-storage-engine.html)表名为`mysql.slave_relay_log_info`.通过使用这个事务性存储引擎，信息总是可以在重新启动时恢复。对应用程序元数据存储库的更新与事务一起提交，这意味着该存储库中记录的副本的进度信息始终与已应用于数据库的内容一致，即使在服务器意外停机的情况下也是如此。有关应用程序元数据存储库的更多信息，请参阅[第 17.2.4 节，“中继日志和复制元数据存储库”](replica-logs.html).

DML 事务和原子 DDL 更新副本的应用程序元数据存储库中的复制位置`mysql.slave_relay_log_info`表连同将更改应用到数据库，作为原子操作。在所有其他情况下，包括不完全原子的 DDL 语句，以及不支持原子 DDL 的豁免存储引擎，`mysql.slave_relay_log_info`如果服务器意外停止，表可能会丢失与复制数据相关的更新。在这种情况下，恢复更新是一个手动过程。有关 MySQL 8.0 中原子 DDL 支持的详细信息，以及某些语句复制的结果行为，请参阅[第 13.1.1 节，“原子数据定义语句支持”](atomic-ddl.html).

副本从意外停止中恢复的恢复过程因副本的配置而异。恢复过程的细节受所选择的复制方法、副本是单线程还是多线程以及相关系统变量的设置的影响。恢复过程的总体目标是确定在发生意外停止之前已在副本的数据库上应用了哪些事务，并检索并应用在意外停止后副本丢失的事务。

-   对于基于 GTID 的复制，恢复过程需要副本已接收或提交的事务的 GTID。可以使用 GTID 自动定位从源中检索丢失的事务，它会自动将源的事务与副本的事务进行比较并识别丢失的事务。

-   对于基于文件位置的复制，恢复过程需要一个准确的复制 SQL 线程（应用程序）位置，以显示应用于副本的最后一个事务。基于该位置，复制 I/O 线程（接收器）从源的二进制日志中检索应从该点开始应用于副本的所有事务。

    使用基于 GTID 的复制可以最容易地配置复制以应对意外停止。GTID 自动定位意味着副本可以可靠地识别和检索丢失的事务，即使应用事务的序列中存在间隙。

    以下信息提供了适用于不同类型副本的设置组合，以保证在复制控制下进行恢复。

重要的

复制无法控制的某些因素可能会影响复制恢复过程以及恢复过程后的整体复制状态。特别是，影响各个存储引擎的恢复过程的设置可能会在副本意外停止的情况下导致事务丢失，因此无法用于复制恢复过程。这[`innodb_flush_log_at_trx_commit=1`](innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit)下面列表中提到的设置是复制设置的关键设置，它使用[`InnoDB`](innodb-storage-engine.html)与交易。但是，其他特定于[`InnoDB`](innodb-storage-engine.html)或其他存储引擎，尤其是与刷新或同步相关的存储引擎，也会产生影响。始终检查并应用您选择的存储引擎提出的有关崩溃安全设置的建议。

副本上的以下设置组合对意外停止最具弹性：

-   当使用基于 GTID 的复制时 ([`gtid_mode=ON`](replication-options-gtids.html#sysvar_gtid_mode)）， 放`SOURCE_AUTO_POSITION=1`\|`MASTER_AUTO_POSITION=1`，它为与源的连接激活 GTID 自动定位，以自动识别和检索丢失的事务。此选项使用[`将复制源更改为`](change-replication-source-to.html)语句（来自 MySQL 8.0.23）或[`将主更改为`](change-master-to.html)语句（在 MySQL 8.0.23 之前）。如果副本有多个复制通道，则需要为每个通道单独设置此选项。有关 GTID 自动定位如何工作的详细信息，请参阅[第 17.1.3.3 节，“GTID 自动定位”](replication-gtids-auto-positioning.html).当使用基于文件位置的复制时，`SOURCE_AUTO_POSITION=1`\|`MASTER_AUTO_POSITION=1`不使用，而是使用二进制日志位置或中继日志位置来控制复制开始的位置。

-   从 MySQL 8.0.27 开始，当使用基于 GTID 的复制时 ([`gtid_mode=ON`](replication-options-gtids.html#sysvar_gtid_mode)）， 放`GTID_ONLY=1`，这使得副本在恢复过程中仅使用 GTID，并停止在复制元数据存储库中保留二进制日志和中继日志文件名和文件位置。此选项使用[`将复制源更改为`](change-replication-source-to.html)陈述。如果副本有多个复制通道，您需要为每个通道单独设置此选项。和`GTID_ONLY=1`，在恢复期间，文件位置信息被忽略，GTID 自动跳过用于跳过已经提供的事务，而不是识别正确的文件位置。如果您使用默认设置清除中继日志，则此策略更有效[`relay_log_purge`](replication-options-replica.html#sysvar_relay_log_purge)，这意味着只需要检查一个中继日志文件。

-   放[`sync_relay_log=1`](replication-options-replica.html#sysvar_sync_relay_log)，它指示复制接收器线程在每个接收到的事务写入到它之后将中继日志同步到磁盘。这意味着从源的二进制日志（在应用程序元数据存储库中）读取的当前位置的副本记录永远不会领先于中继日志中保存的事务记录。请注意，尽管此设置是最安全的，但由于涉及的磁盘写入次数，它也是最慢的。和`同步中继日志 > 1`， 要么`sync_relay_log=0`（同步由操作系统处理），如果副本意外停止，则可能存在尚未同步到磁盘的已提交事务。如果正在恢复的副本根据上次同步到磁盘的中继日志中的信息尝试再次检索和应用事务而不是跳过它们，则此类事务可能会导致恢复过程失败。环境`sync_relay_log=1`对于多线程副本尤其重要，如果无法使用中继日志中的信息填充事务序列中的间隙，则恢复过程将失败。对于单线程副本，只有在应用程序元数据存储库中没有相关信息时，恢复过程才需要使用中继日志。

-   放[`innodb_flush_log_at_trx_commit=1`](innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit)，它同步[`InnoDB`](innodb-storage-engine.html)在提交每个事务之前记录到磁盘。此设置是默认设置，可确保[`InnoDB`](innodb-storage-engine.html)表和[`InnoDB`](innodb-storage-engine.html)日志保存在磁盘上，因此不再需要中继日志中有关事务的信息。结合设置[`sync_relay_log=1`](replication-options-replica.html#sysvar_sync_relay_log)，此设置进一步确保了[`InnoDB`](innodb-storage-engine.html)表和[`InnoDB`](innodb-storage-engine.html)日志始终与中继日志的内容保持一致，因此在意外停止的情况下，清除中继日志文件不会导致副本的事务历史记录中出现无法填补的空白。

-   放[`relay_log_info_repository = 表`](replication-options-replica.html#sysvar_relay_log_info_repository)，它将复制 SQL 线程位置存储在[`InnoDB`](innodb-storage-engine.html)桌子`mysql.slave_relay_log_info`，并将其与事务提交一起更新，以确保记录始终准确。此设置是 MySQL 8.0 的默认设置，并且`文件`设置已弃用。从 MySQL 8.0.23 开始，系统变量本身的使用已被弃用，因此省略它并允许它默认。如果`文件`使用设置，这是早期版本中的默认设置，信息存储在数据目录中的文件中，该文件在应用事务后更新。这会产生失去与源同步的风险，具体取决于副本在处理事务的哪个阶段停止，甚至文件本身的损坏。随着设置[`relay_log_info_repository = 文件`](replication-options-replica.html#sysvar_relay_log_info_repository), 不能保证恢复。

-   放[`relay_log_recovery = ON`](replication-options-replica.html#sysvar_relay_log_recovery)，这将在服务器启动后立即启用自动中继日志恢复。这个全局变量默认为`离开`并且在运行时是只读的，但您可以将其设置为`在`与[`--中继日志恢复`](replication-options-replica.html#sysvar_relay_log_recovery)副本意外停止后副本启动时的选项。请注意，此设置会忽略现有的中继日志文件，以防它们损坏或不一致。中继日志恢复过程启动一个新的中继日志文件，并从记录在应用程序元数据存储库中的复制 SQL 线程位置开始从源获取事务。副本的正常清除机制会随着时间的推移删除先前的中继日志文件。

    对于多线程副本，设置[`relay_log_recovery = ON`](replication-options-replica.html#sysvar_relay_log_recovery)自动处理已从中继日志执行的事务序列中的任何不一致和间隙。当使用基于文件位置的复制时，可能会出现这些间隙。（有关详细信息，请参阅[第 17.5.1.34 节，“复制和事务不一致”](replication-features-transaction-inconsistencies.html).) 中继日志恢复过程使用与[`开始复制直到 SQL_AFTER_MTS_GAPS`](start-replica.html)（或在 MySQL 8.0.22 之前，使用 START SLAVE 而不是 START REPLICA）语句。当副本达到一致的无间隙状态时，中继日志恢复过程继续从复制 SQL 线程位置开始从源获取更多事务。当使用基于 GTID 的复制时，从 MySQL 8.0.18 开始，多线程副本首先检查是否`MASTER_AUTO_POSITION`被设定为`在`，如果是，则省略计算应该跳过或不跳过的事务的步骤，以便恢复过程不需要旧的中继日志。
