

# 配置准则
<a name="rds-proxy-best-practices.configuration"></a>

本节介绍了 RDS 代理中可用的设置，并提供了在应用程序堆栈中协调配置的最佳实践。这些是将 RDS 代理与 Amazon RDS 和 Amazon Aurora 一起使用的综合指南。在适用的情况下，会标出 RDS 特定的注释和 Aurora 特定的注释。

除非另行说明，否则术语“数据库”或“目标”是指 Aurora 集群、Amazon RDS Multi-AZ 数据库集群或 Amazon RDS 实例。

**Topics**
+ [RDS 代理的设置](#rds-proxy-best-practices.configuration-settings)
+ [协调应用程序、代理和数据库配置](#rds-proxy-best-practices.configuration.alignment)
+ [数据库配置](#rds-proxy-best-practices.configuration.alignment.database)
+ [应用程序配置](#rds-proxy-best-practices.configuration.alignment.application)

## RDS 代理的设置
<a name="rds-proxy-best-practices.configuration-settings"></a>

### MaxConnectionsPercent
<a name="rds-proxy-best-practices.configuration.maxconnectionspercent"></a>


| 最小值 | 最大值 | 默认值 | 
| --- | --- | --- | 
| 1 和 MaxIdleConnectionsPercent 中的较小值 | 100 | 100 | 

有关更多信息，请参阅 [MaxConnectionsPercent](rds-proxy-connections.md#rds-proxy-connection-pooling-tuning.maxconnectionspercent)。

此设置限制 RDS 代理可以与目标数据库建立的连接数量，按照数据库允许的最大连接数的百分比来计算。代理会根据需要打开后端连接，因此在任何给定时间的实际连接数可能低于配置的最大值。

鉴于 `MaxConnectionsPercent` 设置是指数据库连接限制的百分比，代理的连接池大小将自动遵循数据库配置。这意味着，每当您调整数据库实例大小或进行配置更改时，无需重新配置代理。这也意味着您需要关注数据库设置可能发生更改的情况，无论是隐式更改还是显式更改：
+ 如果您没有在数据库参数组中明确设置连接限制（例如 `max_connections` 参数），Amazon RDS 和 Aurora 会根据数据库实例类自动计算该限制。因此，在扩展数据库实例时，隐式连接限制可能会发生变化，从而影响代理中的最大池大小。有关更多信息，请参阅《Amazon RDS 用户指南》中的[最大数据库连接数](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.MaxConnections)**，以及《Amazon Aurora 用户指南》中的[至 Aurora MySQL 数据库实例的最大连接数](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Managing.Performance.html#AuroraMySQL.Managing.MaxConnections)和[至 Aurora PostgreSQL 数据库实例的最大连接数](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Managing.html#AuroraPostgreSQL.Managing.MaxConnections)**。
+ Aurora Serverless v2 数据库实例根据数据库配置的最大 ACU 数来确定连接限制。有关详细信息，请参阅《Amazon Aurora 用户指南》**中的 [Aurora Serverless v2 的最大连接数](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.setting-capacity.html#aurora-serverless-v2.max-connections)。

最佳实践：
+ 默认设置为 100%，适用于那些通过代理接收所有流量，并且不需要为管理访问或其他客户端预留任何余量的数据库。
+ 如果数据库还直接从应用程序接收流量（绕过代理）并且您不希望代理占用所有连接，或者您希望为其他用途（例如数据库管理员进行的直接访问）保留一定数量的连接，请减少此设置。
+ 在将 RDS 代理与 Aurora Global Database 集群一起使用并启用写入转发时，减小代理的 `MaxConnectionsPercent` 值，减小额等于为写入转发分配的配额。有关详细信息，请参阅《Amazon Aurora 用户指南》**中的 [Aurora MySQL](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-global-database-write-forwarding-ams.html#aurora-global-database-write-forwarding-params-ams) 和 [Aurora PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-global-database-write-forwarding-apg.html#aurora-global-database-write-forwarding-params-apg) 中写入转发的配置参数。无论代理是为全局数据库的主区域还是辅助区域的集群提供服务，此建议均适用。辅助集群可以提升为主集群，因此在整个全球拓扑中保持代理设置一致性是一种好的做法。对于为主区域与辅助区域提供服务的代理，您*可以*使用非对称设置，但是在每次全局失效转移或切换之后，都需要调整这些设置。
+ 如果目标为多个代理提供服务，则所有这些代理的 `MaxConnectionsPercent` 组合值不得超过 100，以免数据库超额订阅。我们建议每个目标使用一个代理，以简化配置和管理。特别是，您不需要为每个数据库使用多个代理来实现冗余。有关更多信息，请参阅 [对一个目标使用多个代理](rds-proxy-best-practices.usage-scenarios.md#rds-proxy-best-practices.multiple-proxies)。

无论您使用默认 `MaxConnectionsPercent` 设置还是自定义值，都要在允许的连接数与高峰期预期的最大客户端连接数之间保持至少 30% 的余量。例如：
+ 如果您认为代理所需连接最高为数据库所配置的连接限制的 50%，`MaxConnectionsPercent` 设置必须至少设定为 `1.3 * 50% = 65%`。
+ 使用 `MaxConnectionsPercent` 默认设置 100 时，请确保数据库限制自身能够提供足够的余量。

这种额外余量在出现意外工作负载激增时可以改善客户端体验，并帮助 RDS 代理在其内部基础设施中重新分配连接，以进行热管理和实现其他用途。

尽管您可以将 `MaxConnectionsPercent` 设置为低至 1 的值，但我们建议根据实例类型设置以下最小值：
+ db.t3.small：100
+ db.t3.medium：55
+ db.t3.large：35
+ db.r3.large 或更大：20

### MaxIdleConnectionsPercent
<a name="rds-proxy-best-practices.configuration.maxidleconnectionspercent"></a>


| 最小值 | 最大值 | 默认值（SQL Server） | 默认值（其他引擎） | 
| --- | --- | --- | --- | 
| （零） | MaxConnectionsPercent | MaxConnectionsPercent 的 5% | MaxConnectionsPercent 的 50% | 

有关更多信息，请参阅 [MaxIdleConnectionsPercent](rds-proxy-connections.md#rds-proxy-connection-pooling-tuning.maxidleconnectionspercent)。

此设置限制 RDS 代理在连接池中保持的空闲数据库连接数量，按照数据库允许的最大连接数的百分比来计算。当连接在五分钟内没有任何活动时，数据库（后端）连接被视为空闲。此设置适用于代理与后端数据库之间的连接。

请注意以下几点：
+ 此设置限制连接池中空闲连接的数量，但不会强制代理保留特定数量的空闲连接。如果客户端活动非常少，后端数据库的实际连接数可能会低于 `MaxIdleConnectionsPercent`。
+ 当连接可供在代理的连接池中重复使用时，这样的连接被视为空闲连接。固定连接不能被其他客户端重复使用，因此在强制实施 `MaxIdleConnectionsPercent` 时不计作空闲连接。有关固定的更多信息，请参阅[避免固定 RDS 代理](rds-proxy-pinning.md)。
+ 数据库元数据报告的空闲连接数通常高于 RDS 代理指标记录的空闲连接数。这可能是由于直接客户端连接绕过代理，以及 Amazon RDS 和 Aurora 自动化使用的内部连接所导致的。

**注意**  
在代理层观察和强制实施的连接空闲时间可能与数据库工具（例如 MySQL 进程列表或 PostgreSQL 的活动统计表）报告的空闲时间有所不同。RDS 代理会偶尔对后端连接发送 ping，这会重置数据库的空闲计时器，即使从客户端活动角度看连接处于空闲状态也是如此。

最佳实践：

对于大多数工作负载而言，默认设置 50 比较合适，推荐使用该设置。更改设置具有以下影响：
+ 当您增大 `MaxIdleConnectionsPercent` 时，数据库会观察到更多的空闲连接，这可能会在高峰时段之外增加数据库资源消耗。另一方面，通过代理处理的连接峰值遇到的借用延迟会更低，因为池中随时可用的连接更多。
+ 当您降低 `MaxIdleConnectionsPercent` 时，代理会更积极地关闭空闲连接，从而可能减少这些连接引起的争用和资源消耗。不过，通过代理处理的连接峰值遇到的借用时间会更长。由于池中的可用连接较少，代理在流量激增时需要花费额外时间来打开新的后端连接。

在使用预调配实例类型的数据库中，空闲连接的资源消耗可能不是一个重大问题，但使用 Serverless v2 实例类型的 Aurora 数据库可能会希望优化闲置资源消耗来降低成本。

### IdleClientTimeout
<a name="rds-proxy-best-practices.configuration.idleclienttimeout"></a>


| 最小值 | 最大值 | 默认值 | 
| --- | --- | --- | 
| 1 minute | 8 小时 | 30 分钟 | 

有关更多信息，请参阅 [IdleClientTimeout](rds-proxy-connections.md#rds-proxy-connection-pooling-tuning.idleclienttimeout)。

此设置决定客户端连接在被代理关闭之前可以保持空闲的时间。请注意，RDS 代理会强制实施 24 小时的最大连接生命周期，无论连接是否处于空闲状态都是如此。例如，如果您将 `IdleClientTimeout` 配置为 30 分钟（默认值）并且每分钟对数据库执行一次 ping 操作，则连接永远不会超过空闲超时，但也不会无限期地保持打开状态。即使连接不符合空闲条件，RDS 代理也会在 24 小时后关闭连接。

`IdleClientTimeout` 设置适用于客户端（应用程序或交互式用户）与 RDS 代理之间的连接。要了解 RDS 代理与数据库之间的后端连接的空闲行为，请参阅 [MaxIdleConnectionsPercent](#rds-proxy-best-practices.configuration.maxidleconnectionspercent)。

最佳实践：
+ 空闲超时时间必须足够长，以包含客户端连接或事务内 SQL 活动的正常暂停。时间不应过长，以便使客户端保留在合理角度上不再需要而其他客户端可能需要的资源。如果您观察到连接固定，这尤其重要，因为一个客户端固定的连接无法被其他客户端重复使用。
+ 为了让 RDS 代理正确强制实施超时，客户端连接必须真正处于空闲状态，而不发送任何查询（即使是简单的运行状况检查，例如 `SELECT 1;`）或协议 ping 操作（例如 MySQL 中的 `COM_PING`）。如果您观察到连接在超过超时时间后仍未关闭，请检查您的应用程序驱动程序的连接逻辑。应用程序级连接池特别容易执行自己的活跃度检查，从而对 `IdleClientTimeout` 产生干扰。

### ConnectionBorrowTimeout
<a name="rds-proxy-best-practices.configuration.connectionborrowtimeout"></a>


| 最小值 | 最大值 | 默认值 | 
| --- | --- | --- | 
| （零） | 5 分钟 | 2 分钟 | 

有关更多信息，请参阅 [ConnectionBorrowTimeout](rds-proxy-connections.md#rds-proxy-connection-pooling-tuning.connectionborrowtimeout)。

当客户端连接到 RDS 代理时，代理必须从池中借用现有可用连接或打开一个新的数据库连接。此设置定义 RDS 代理在返回错误之前等待连接被借用或打开的时间长度。

请注意以下几点：
+ 当连接池中尚未存在可用连接时，将 `ConnectionBorrowTimeout` 设置为零会导致超时错误。即使连接池未达到最大容量，并且可以打开新的后端连接，也是如此。
+ 即使 `MaxIdleConnectionsPercent` 等于 `MaxConnectionsPercent`，连接池中的实际连接数也可能低于配置的最大值。换句话说，`MaxIdleConnectionsPercent` 会限制空闲连接的数量，但不强制连接保持打开状态。

连接池运行时的容量低于最大容量是正常的。在这种情况下，将 `ConnectionBorrowTimeout` 设置为零可以防止连接池增长，因为连接池不允许等待打开新连接。因此，除非偏好采用先前描述的行为，否则您应该为所有工作负载使用非零的 `ConnectionBorrowTimeout` 值。

**注意**  
如果数据库尚未准备好接受连接（例如在离线维护操作和失效转移期间），此设置也适用。无论数据库是处于启动还是关闭状态，强制实施 `ConnectionBorrowTimeout` 的逻辑都是相同的。

### 初始化查询和固定过滤器
<a name="rds-proxy-best-practices.configuration.pinning-filters"></a>

RDS 代理支持其他一些功能，这些功能可以减少连接固定，从而提高多路复用效率。

**初始化查询**是指在代理每次建立新的后端数据库连接时，运行一条或多条语句。如果您的客户端使用相同的语句来设置会话参数，您可以将这些语句移动到代理的初始化查询中。这有助于降低连接固定的可能性，同时也提高了效率：一个具体的后端数据库连接在设置期间只运行一次初始化查询，但之后可能被许多客户端重复使用。请记住，将 SQL 语句放入初始化查询中并不会将这些语句从客户端流量中过滤掉。您仍然需要从应用程序代码中移除那些语句，以免它们干扰多路复用。

**会话固定过滤器**是一种配置属性，用于防止代理固定某些会话状态。目前唯一可用的过滤器选项是 `EXCLUDE_VARIABLE_SETS`，指示代理在确定是否应固定会话时忽略所有 `SET` 语句。这些 `SET` 语句仍然会传递到数据库，并可能影响会话状态，这意味着此选项仅在以下情况下是安全的：

1. 这些 `SET` 语句的结果没有任何效果，例如将系统变量设置为与服务器默认值相同的值。

1. 这些 `SET` 语句和随后的查询属于同一个事务，每个事务都会完全独立地设置各自的状态，因此不会受到其他事务所设置变量的影响。

**注意**  
`EXCLUDE_VARIABLE_SETS` 固定过滤器是一个全有或全无的设置，您无法选择性地忽略特定的 `SET` 语句。除非您的使用案例属于前面列表中讨论的某一类别，否则不要将此过滤器作为针对固定的一揽子解决方案。

为了获得最佳效果，应尽可能从应用程序代码中删除不必要的语句，并且仅在无法修改应用程序时才使用过滤器。这样得到的客户端/服务器环境干扰因素较少且更可预测，而不是对本来不需要的语句进行特殊处理。

**重要**  
初始化查询和固定过滤器都不会导致 RDS 代理变更客户端/服务器查询流量。来自客户端的语句仍然会传递到数据库，而无论初始化查询或固定过滤器配置如何。

有关更多信息，请参阅：
+ [为 Amazon RDS 创建代理](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-creating.html)和[为 Amazon RDS 修改代理](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-modifying-proxy.html)。
+ [为 Amazon Aurora 创建代理](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/rds-proxy-creating.html)和[为 Amazon Aurora 修改代理](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/rds-proxy-modifying-proxy.html)。

对于 PostgreSQL 连接，您也可以将支持的连接参数放在客户端驱动程序与代理之间交换的启动消息中。这避免了发送单独的 `SET` 命令，从而既减少往返次数，又避免由显式 `SET` 语句引起的连接固定。有关更多信息，请参阅 [连接到 PostgreSQL 的注意事项](rds-proxy-connecting.md#rds-proxy-connecting-postgresql)。

## 协调应用程序、代理和数据库配置
<a name="rds-proxy-best-practices.configuration.alignment"></a>

如前一节所讨论的那样，RDS 代理支持一系列参数，帮助您将代理行为与应用程序需求保持一致。不过，选择正确的配置值是一项涉及堆栈各个层的任务：应用程序、代理和数据库本身。所有这些组件的设置都必须与以下目标保持一致：

1. 在正常操作期间提供预期水平的性能和可扩展性。

1. 在出现工作负载问题期间为故障排除提升清晰度和便利性。

1. 推动堆栈以最小的应用程序影响应对意外事件（例如工作负载骤增）。

在多层环境中选择和微调设置时，尽量使配置值保持协调一致，以便较低层的限制和超时值等于或高于较高层的相应限制和超时值。换而言之，将某一层的设置视为一个信封，它需要能够放入堆栈中更下一层的配置信封中。

例如，假设您的应用程序是顶层，代理是中间层，而数据库是底层。如果代理级别的超时和限制低于应用程序级别的限制，则代理限制优先于应用程序限制。应用程序无法执行其设置，并且会出现无法通过自身配置解释的行为。

以 `IdleClientTimeout` 代理设置为例。如果您的应用程序驱动程序或客户端池强制实施自己的空闲超时，则代理的空闲超时是应用程序设置之外的安全保障。这意味着 `IdleClientTimeout` 必须至少等于应用程序级别的任何空闲超时，以防止混淆：
+ 当应用程序空闲超时低于代理超时时，您期望应用程序按照配置的方式关闭其连接。如果应用程序未能及时关闭空闲连接，代理将作为最后防线。
+ 当应用程序空闲超时大于代理超时时，应用程序可能会遇到被认为过早关闭连接的情况。这可能会导致应用程序端发生混乱。

同样的逻辑也适用于其他设置，例如连接限制：每一层的设置都应该纳入到下一层配置所定义的范围内。

为了获得最佳效果，配置设置应在某一层与下一层之间留出一些空隙。例如，您可以将代理超时设置为比应用程序超时稍长几秒，以避免由于客户端/服务器时钟漂移导致的偶发错误，或者以防客户端需要额外时间来正常关闭连接。

换句话说，按照下面的方式协调您的设置：

`client timeout < proxy timeout < database timeout`

不应进行如下查询：

`client timeout = proxy timeout = database timeout`

并且避免出现下面的情况：

`client timeout > proxy timeout > database timeout`

## 数据库配置
<a name="rds-proxy-best-practices.configuration.alignment.database"></a>

### 连接限制
<a name="rds-proxy-database-connection-limits"></a>

RDS 代理使用 `MaxConnectionsPercent` 设置来确定其连接池的最大大小，这意味着代理的连接池大小与数据库的连接限制相关。当您更改数据库的连接限制时，代理的连接池大小会自动随之更改。如果您希望数据库为非代理用户保留部分连接限制，则应该通过降低代理中的 `MaxConnectionsPercent` 设置来实现，而不是通过增加数据库限制。

RDS 代理并不能消除对数据库连接限制进行适当配置的需求。单个代理连接本身并不比单个直接客户端连接更加轻量，因此不要只因为使用代理就增加数据库限制。代理不会减少数据库处理查询所需的工作量，但它可以帮助数据库通过更少的连接处理相同的工作负载。

### 空闲超时
<a name="rds-proxy-database-idle-timeouts"></a>

数据库可以强制实施自己的空闲超时，例如，使用 MySQL 中的 `wait_timeout` 和 `interactive_timeout` 设置或 PostgreSQL 中的 `transaction_timeout` 和 `idle_in_transaction_session_timeout` 设置。这些设置的默认值不太可能干扰代理配置，但如果您使用自定义的数据库级别超时，请确保它们至少与相应的代理超时一样长，否则代理可能会因过早超时而发生连接错误。

同样的逻辑也适用于使用连接终止器的数据库环境，这些终止器是监控会话状态并根据特定标准主动终止连接的脚本或进程。如果您的环境使用此类技术，请确保连接终止逻辑与代理设置一致。

通过代理处理所有工作负载的数据库通常可以依赖代理配置来设置空闲超时，并将数据库级别的设置保持为默认值。

## 应用程序配置
<a name="rds-proxy-best-practices.configuration.alignment.application"></a>

### 管理会话状态
<a name="rds-proxy-managing-session-state"></a>

许多数据库驱动程序、应用程序框架和对象关系映射（ORM）工具会在发送查询流量之前，使用会话变量或 `SET` 语句来建立连接。单独从应用程序代码的角度看，连接和事务初始化语句的使用可能并不明显，并且在数据库本身与 SQL 语句和应用程序逻辑之间可能存在多个抽象层。您可以使用 RDS 代理增强型日志记录功能来记录连接固定的原因，而数据库查询日志可以提供有关通过数据库连接发送的所有语句的更多信息。

考虑下面的最佳实践：

1. 仅当连接参数与数据库默认值不同并且客户端会话必须偏离这些默认值时，才设置连接参数。删除不必要的初始化语句不仅有助于多路复用，还可以减少每个新数据库连接的客户端/服务器往返次数。

1. 在所有连接中一致地设置变量和配置设置。

1. 避免使用还可以在查询运行时应用的会话配置。例如，如果不同的客户端需要查看不同时区的数据，则考虑在查询级别使用时区转换函数，而不是在会话级别设置时区。

1. 尽可能使用初始化查询功能将会话配置语句移到代理层。有关更多详细信息，请参阅[初始化查询和固定过滤器](#rds-proxy-best-practices.configuration.pinning-filters)。

### 活跃度检查
<a name="rds-proxy-best-practices.configuration.alignment.healthchecks"></a>

如果您的应用程序使用连接池或高级驱动程序，请查找与活跃度检查相关的配置，例如协议 ping、运行状况检查语句或“保持连接”查询。RDS 代理以等同方式处理所有客户端请求，因此即使 `SELECT 1;` 查询或 `COM_PING` 请求从应用程序的角度来看没有任何效果，它也会阻止代理强制实施空闲客户端超时并根据 `MaxIdleConnectionsPercent` 管理连接池大小。

**注意**  
RDS 代理强制实施的最大连接生命周期为 24 小时，而无论连接上的活动如何。

在大多数情况下，禁用客户端的活跃度检查可能是合适的，这样可以减少协议干扰因素并帮助 RDS 代理管理空闲连接。在某些边缘情况下，您可能希望无论如何都要运行这些运行状况检查：
+ 您特意要防止某些连接在代理层超时。
+ 您希望允许应用程序驱动程序或连接池主动检测连接何时被代理断开。例如，由于数据库重启，固定的后端连接可能会被关闭，并且客户端连接可能会超过 24 小时的最长生命周期。

考虑在应用程序端禁用活跃度检查，或者只对您希望保持不超时的特定连接执行这些检查。

### 会话状态跟踪
<a name="rds-proxy-best-practices.configuration.alignment.statetracking"></a>

一些 MySQL 数据库驱动程序（例如 MariaDB 驱动程序）使用 `session_track_*` 变量来跟踪会话状态。启用此功能后，每当客户端执行服务器可跟踪的会话状态更改时，服务器会在其响应数据包中包含状态更改信息。这使得服务器能够向驱动程序提供有关会话状态的通知。

当客户端直接与服务器交互并实现自己的会话管理功能（例如在多服务器环境中的会话迁移）时，这种会话状态跟踪方式可能是有意义的。RDS 代理实现了自己的状态跟踪机制，并且不使用通过 `session_track_*` 变量启用的信息，而设置这些变量会导致会话固定。

如果您的数据库驱动程序设置了这些变量，您可以想办法在驱动程序中禁用跟踪功能，切换到不同的驱动程序，或者在安全情况下使用会话固定过滤器来忽略这些语句。有关更多详细信息，请参阅[初始化查询和固定过滤器](#rds-proxy-best-practices.configuration.pinning-filters)。