

# 优化 Aurora MySQL 的二进制日志复制
<a name="binlog-optimization"></a>

 接下来，您可以了解如何优化二进制日志复制性能和排查 Aurora MySQL 中的相关问题。

**提示**  
 本讨论假定您熟悉 MySQL 二进制日志复制机制及其工作原理。有关背景信息，请参阅 MySQL 文档中的[复制实施](https://dev.mysql.com/doc/refman/8.0/en/replication-implementation.html)。

## 多线程二进制日志复制
<a name="binlog-optimization-multithreading"></a>

使用多线程二进制日志复制时，SQL 线程会从中继日志中读取事件并将其排队，以便 SQL 工作线程应用。SQL 工作线程由协调器线程管理。尽可能并行应用二进制日志事件。并行度级别取决于版本、参数、架构设计和工作负载特性等因素。

Aurora MySQL 版本 3 和 Aurora MySQL 2.12.1 及更高版本支持多线程二进制日志复制。为了使多线程副本能够高效地并行处理二进制日志事件，您必须为多线程二进制日志复制配置源，并且源使用的版本必须包含有关其二进制日志文件中的并行度信息。

当 Aurora MySQL 数据库实例配置为使用二进制日志复制时，默认情况下，副本实例对低于 3.04 的 Aurora MySQL 版本使用单线程复制。要启用多线程复制，请在您的自定义参数组中将 `replica_parallel_workers` 参数更新为大于 `1` 的值。

对于 Aurora MySQL 版本 3.04 及更高版本，复制默认是多线程的，`replica_parallel_workers` 设置为 `4`。您可以在自定义参数组中修改此参数。

为了提高数据库在意外中断时的弹性，我们建议您在源上启用 GTID 复制，并在副本上支持 GTID。要支持 GTID 复制，请同时在源和副本上将 `gtid_mode` 设置为 `ON_PERMISSIVE`。有关基于 GTID 的复制的更多信息，请参阅[使用基于 GTID 的复制](mysql-replication-gtid.md)。

以下配置选项可以帮助您优化多线程复制。有关使用信息，请参阅 *MySQL 参考手册*中的[复制和二进制日志记录选项和变量](https://dev.mysql.com/doc/refman/8.0/en/replication-options.html)。有关多线程复制的更多信息，请参阅 MySQL 博客 [https://dev.mysql.com/blog-archive/improving-the-parallel-applier-with-writeset-based-dependency-tracking/](https://dev.mysql.com/blog-archive/improving-the-parallel-applier-with-writeset-based-dependency-tracking/)。

最佳参数值取决于多个因素。例如，二进制日志复制的性能受数据库工作负载特征和副本运行所在的数据库实例类的影响。因此，建议您在将新参数设置应用于生产实例之前，彻底测试对这些配置参数的所有更改：
+ `binlog_format recommended value` – 设置为 `ROW`
+ `binlog_group_commit_sync_delay`
+ `binlog_group_commit_sync_no_delay_count`
+ `binlog_transaction_dependency_history_size`
+ `binlog_transaction_dependency_tracking`：建议值为 `WRITESET`
+ `replica_preserve_commit_order`
+ `replica_parallel_type`：建议值为 `LOGICAL_CLOCK`
+ `replica_parallel_workers`
+ `replica_pending_jobs_size_max`
+ `transaction_write_set_extraction`：建议值为 `XXHASH64`

您的架构和工作负载特征是影响并行复制的因素。最常见的因素如下。
+ 缺少主键：RDS 无法为没有主键的表建立写集依赖关系。使用 `ROW` 格式，可以通过在源上进行单次全表扫描来完成单个多行语句，但会导致对在副本上修改的每一行都进行一次完整表扫描。缺少主键会显著降低复制吞吐量。
+ 存在外键：如果存在外键，Amazon RDS 就无法使用写集依赖关系来实现表与 FK 关系的并行性。
+ 事务大小：如果单个事务跨越数十或数百兆字节或千兆字节，则协调器线程和其中一个工作线程可能会花很长时间只处理该事务。在此期间，所有其它工作线程在完成对先前事务的处理后可能会保持空闲状态。

在 Aurora MySQL 版本 3.06 及更高版本中，在为具有多个二级索引的大型表复制事务时，可以提高二进制日志副本的性能。此功能引入了一个线程池，用于在二进制日志副本上并行应用二级索引更改。该功能由 `aurora_binlog_replication_sec_index_parallel_workers` 数据库集群参数控制，该参数控制可用于应用二级索引更改的并行线程总数。默认情况下，此参数设置为 `0`（禁用）。启用此功能不需要重启实例。要启用此功能，请停止正在进行的复制，设置所需的并行工作线程数，然后重新开始复制。

## 优化二进制日志复制
<a name="binlog-optimization-binlog-io-cache"></a><a name="binlog_boost"></a><a name="binlog_io_cache"></a>

 在 Aurora MySQL 2.10 及更高版本中，Aurora 会自动将称为二进制日志 I/O 缓存的优化应用于二进制日志复制。通过缓存最近提交的二进制日志事件，此优化旨在提高二进制日志转储线程性能，同时限制对二进制日志源实例上前台事务的影响。

**注意**  
 用于此功能的内存独立于 MySQL `binlog_cache` 设置。  
 此功能不适用于使用 `db.t2` 和 `db.t3` 实例类的 Aurora 数据库实例。

您无需调整任何配置参数即可启用此优化。特别是，如果您在早期 Aurora MySQL 版本中曾将配置参数 `aurora_binlog_replication_max_yield_seconds` 调整为非零值，请为当前可用版本设置回零。

状态变量 `aurora_binlog_io_cache_reads` 和 `aurora_binlog_io_cache_read_requests` 可帮助您监控从二进制日志 I/O 缓存读取数据的频率。
+  `aurora_binlog_io_cache_read_requests` 显示来自缓存的二进制日志输入/输出读取请求的数量。
+  `aurora_binlog_io_cache_reads` 显示从缓存检索信息的二进制日志输入/输出读取的数量。

 以下 SQL 查询计算利用缓存信息的二进制日志读取请求的百分比。在此情况下，比率越接近 100，就越好。

```
mysql> SELECT
  (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS
    WHERE VARIABLE_NAME='aurora_binlog_io_cache_reads')
  / (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS
    WHERE VARIABLE_NAME='aurora_binlog_io_cache_read_requests')
  * 100
  as binlog_io_cache_hit_ratio;
+---------------------------+
| binlog_io_cache_hit_ratio |
+---------------------------+
|         99.99847949080622 |
+---------------------------+
```

 二进制日志 I/O 缓存功能还包括与二进制日志转储线程相关的新指标。*转储线程*是当新的二进制日志副本连接到二进制日志源实例时创建的线程。

转储线程指标每 60 秒输出到数据库日志中一次，并带有前缀 `[Dump thread metrics]`。这些指标包括每个二进制日志副本的信息，例如，`Secondary_id`、`Secondary_uuid`、二进制日志文件名以及每个副本读取的位置。这些指标还包括 `Bytes_behind_primary`，表示复制源和副本之间的距离（以字节为单位）。此指标衡量副本 I/O 线程的滞后。该数字不同于副本 SQL 应用程序线程的滞后，后者通过二进制日志副本上的 `seconds_behind_master` 指标表示。您可以通过检查距离是减少还是增加来确定二进制日志副本是跟上源还是落后。

## 内存中继日志
<a name="binlog-optimization-in-memory-relay-log"></a>

在 Aurora MySQL 版本 3.10 及更高版本中，Aurora 引入了称为内存中继日志的优化来提高复制吞吐量。此优化通过在内存中缓存所有中间中继日志内容来增强中继日志 I/O 性能。因此，它通过最大限度地减少存储 I/O 操作来减少提交延迟，因为中继日志内容在内存中仍然保持可供随时访问。

默认情况下，当副本满足以下任何配置时，会自动为 Aurora 托管式复制场景（包括蓝绿部署、Aurora-Aurora 复制以及跨区域副本）启用内存中继日志功能：
+ 单线程复制模式（replica\$1parallel\$1workers = 0）
+ 启用了 GTID 模式的多线程复制：
  + 启用了自动定位
  + 副本上的 GTID 模式设置为 ON
+ 在 replica\$1preserve\$1commit\$1order = ON 时进行基于文件的复制

大于 t3.large 的实例类支持内存中继日志功能，但此功能在 Aurora Serverless 实例上不可用。中继日志循环缓冲区的固定大小为 128 MB。要监控此功能的内存消耗，可以运行以下查询：

```
SELECT event_name, current_alloc FROM sys.memory_global_by_current_bytes WHERE event_name = 'memory/sql/relaylog_io_cache';
```

内存中继日志功能由 aurora\$1in\$1memory\$1relaylog 参数控制，该参数可以在数据库集群或实例级别进行设置。可以在不重新启动实例的情况下动态启用或禁用此功能：

1. 停止正在进行的复制

1. 在参数组中将 aurora\$1in\$1memory\$1relaylog 设置为 ON（启用）或 OFF（禁用）

1. 重新启动复制

示例：

```
CALL mysql.rds_stop_replication;
set aurora_in_memory_relaylog to ON to enable or OFF to disable in cluster parameter group
CALL mysql.rds_start_replication;
```

即使 aurora\$1in\$1memory\$1relaylog 设置为 ON，在某些条件下，内存中继日志功能仍可能被禁用。要验证该功能的当前状态，可以使用以下命令：

```
SHOW GLOBAL STATUS LIKE 'Aurora_in_memory_relaylog_status';
```

如果意外禁用了该功能，则可以通过运行以下命令来确定原因：

```
SHOW GLOBAL STATUS LIKE 'Aurora_in_memory_relaylog_disabled_reason';
```

此命令返回一条消息，解释当前禁用该功能的原因。