

# 排查 MySQL 只读副本问题
<a name="USER_ReadRepl.Troubleshooting"></a>

对于 MySQL 数据库实例，在某些情况下，只读副本将显示只读副本与其源数据库实例之间的复制错误或数据不一致项（或两者）。如果在只读副本或源数据库实例失败期间未刷新某些二进制日志 (binlog) 事件或 InnoDB 重做日志，则会出现此问题。在这些情况下，请手动删除并重新创建只读副本。您可通过设置以下参数值来降低发生这种情况的可能性：`sync_binlog=1` 和 `innodb_flush_log_at_trx_commit=1`。这些设置可能降低性能，因此，请先测试其影响，然后在生产环境中实施更改。

**警告**  
建议在与源数据库实例关联的参数组中保留以下参数值：`sync_binlog=1` 和 `innodb_flush_log_at_trx_commit=1`。这些是动态参数。如果不想使用这些设置，建议在对源数据库实例执行可能导致其重启的任何操作之前，临时设置这些值。这些操作包括但不限于重启、使用故障转移重启、升级数据库版本以及更改数据库实例类或其存储。同样的建议也适用于创建源数据库实例的新只读副本。  
如果不遵循此指示，则将增加只读副本显示只读副本与其源数据库实例之间的复制错误或数据不一致项（或两者）的风险。

MySQL 的复制技术是异步的。由于它们是异步的，因此，源数据库实例上偶发的 `BinLogDiskUsage` 会增多，而只读副本上应有 `ReplicaLag`。例如，对源数据库实例的大量写入操作可以并行进行。与之对比的是，对只读副本的写入操作使用单个 I/O 线程串行进行，这会导致源实例与只读副本之间存在滞后。有关 MySQL 文档中只读副本的更多信息，请参阅[复制实施详细信息](https://dev.mysql.com/doc/refman/8.0/en/replication-implementation-details.html)。

您可通过多种方式来减少对源数据库实例的更新与对只读副本的后续更新之间的滞后，例如：
+ 将只读副本的存储大小和数据库实例类调整到与源数据库实例类似。
+ 确保源数据库实例和只读副本使用的数据库参数组中的参数设置相兼容。有关更多信息和示例，请参阅本部分后面的有关 `max_allowed_packet` 参数的讨论。

Amazon RDS 监控只读副本的复制状态，如果由于任何原因停止复制，则将只读副本实例的 `Replication State` 字段更新为 `Error`。可能会有这样的例子，在您的只读副本上运行的 DML 查询与对源数据库实例的更新冲突。

可通过查看 `Replication Error` 字段，检查 MySQL 引擎引发的关联错误的详细信息。还生成指示只读副本状态的事件，包括 [RDS-EVENT-0045](USER_Events.Messages.md#RDS-EVENT-0045)、[RDS-EVENT-0046](USER_Events.Messages.md#RDS-EVENT-0046) 和 [RDS-EVENT-0047](USER_Events.Messages.md#RDS-EVENT-0047)。有关这些事件和事件订阅的详细信息，请参阅 [使用 Amazon RDS 事件通知](USER_Events.md)。如果返回 MySQL 错误消息，则检查 [MySQL 错误消息文档](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html)中的错误编号。

一个可导致复制出错的常见问题是只读副本的 `max_allowed_packet` 参数的值小于源数据库实例的 `max_allowed_packet` 参数的值。`max_allowed_packet` 参数是您可以在数据库参数组中设置的自定义参数。您可以使用 `max_allowed_packet` 指定可在数据库上运行的 DML 代码的最大大小。有时候，与只读副本关联的数据库参数组中的 `max_allowed_packet` 值，要小于与源数据库实例关联的数据库参数组中的 `max_allowed_packet` 值。在这些情况下，复制过程可能会引发错误 `Packet bigger than 'max_allowed_packet' bytes` 并停止复制。如需修复错误，请让源数据库实例和只读副本使用具有相同 `max_allowed_packet` 参数值的数据库参数组。

其他可导致复制错误的常见情况包括：
+ 对只读副本上的表进行写入操作。在某些情况下，您可能会在只读副本上创建索引，而该索引不同于源数据库实例上的索引。如果执行此操作，请将 `read_only` 参数设置为 `0` 以创建索引。如果您要写入到只读副本上的表，则在只读副本变得与源数据库实例不兼容时，复制会中断。对只读副本执行维护任务之后，我们建议您将 `read_only` 参数调整回 `1`。
+  使用非事务性存储引擎，如 MyISAM。只读副本需要使用事务性存储引擎。仅 MySQL 上的 InnoDB 存储引擎支持复制。
+  使用不安全的不确定性查询，如 `SYSDATE()`。有关更多信息，请参阅[确定二进制日志记录中的安全和不安全语句](https://dev.mysql.com/doc/refman/8.0/en/replication-rbr-safe-unsafe.html)。

如果您确定可安全跳过错误，那么可以按照[跳过 RDS for MySQL 的当前复制错误](Appendix.MySQL.CommonDBATasks.SkipError.md)部分中描述的步骤操作。否则，您可以先删除只读副本。然后，您可以使用相同的数据库实例标识符创建实例，以使终端节点保持与旧只读副本的终端节点相同。如果复制错误得到纠正，则 `Replication State` 将更改为 *replicating*。