在 Amazon RDS MultiAZ 部署中使用 PgBouncer 实现快速切换
by Yuli Khodorkovskiy 和 Rajat Jain 于 2023 年 11 月 16 日 发布于 Amazon RDS
关键要点
借助 AWS 的 PgBouncer 补丁,Amazon RDS MultiAZ 部署在进行小版本升级时的写入停机时间可以减少到通常 1 秒或更少。PgBouncer 是一个开源的 PostgreSQL 连接池管理工具,能够利用新引入的拓扑元数据来预创建连接池,优化切换速度。文章介绍了如何设置 PgBouncer 容器,以便在 Amazon RDS MultiAZ DB 集群中实现更平稳的维护和升级过程。Amazon RDS MultiAZ 部署的 PostgreSQL 现已支持在小版本升级和系统维护更新时,通常 35 秒或更短时间的写入停机。通过使用 AWS 提供的 PgBouncer 补丁,您可以进一步将写入停机时间缩短至通常 1 秒或更少。这大大减少了应用程序在升级期间对依赖数据库的干扰。
PgBouncer 是一个开源的 PostgreSQL 连接池管理工具。为了实现快速切换,AWS 提供的最新 PgBouncer 补丁利用了 Amazon RDS for PostgreSQL 新增的拓扑元数据,在引擎启动时为 Amazon RDS MultiAZ DB 集群中的所有节点预创建连接池。
在本文中,我们将设置 PgBouncer Docker 容器,以在 Amazon RDS MultiAZ DB 集群进行小版本升级时最大限度地减少写入停机时间。我们还将讨论在 Amazon RDS for PostgreSQL 中引入的 API,该 API 公开了 Amazon RDS MultiAZ DB 集群中所有节点的拓扑信息。
什么是切换?
切换是一项计划内的维护活动,客户应用程序流量会按照控制方式从一个数据库主机路由到另一个数据库主机。这在 Amazon RDS MultiAZ DB 集群中进行小版本升级时被启动。
客户端可以选择连接到集群的写入端点或读取端点。通常,他们会连接到写入端点,该端点会指向当前的写入实例。当由于小版本升级导致切换时,某个读取实例会被提升为新的写入实例。Amazon RDS 会自动更新集群端点,以指向新的写入实例,并更新实例端点的 DNS 记录。由于 DNS 传播的固有延迟,这可能需要长达 35 秒的时间才能解析。通常,应用程序需要在数据库暂时不可用后进行重新连接的逻辑。通过 AWS 提供的 PgBouncer 补丁,能够自动检测并切换到新的写入实例。如果您在 RDS for PostgreSQL MultiAZ DB 集群前面使用 PgBouncer,您的应用程序在进行小版本升级时可以在通常 1 秒或更少的时间内切换连接,前提是读取实例没有延迟。
前提条件
为了在小版本升级或系统维护更新时实现 1 秒或更少的停机时间,您需要使用 Amazon RDS for PostgreSQL 154 及以上版本,且需安装 rdstools 扩展 14 或更高版本。如果您已经存在的集群版本符合要求,请升级到至少 R3 版本。此外,您需要使用 AWS 提供的 PgBouncer 快速切换库中的 Dockerfile 创建 PgBouncer 容器。
另外,如果您的数据库不是公共可访问的,您还需要在与集群相同的 VPC 中创建一个 Amazon Elastic Compute Cloud 实例。为了实现最快的切换,我们建议在同一地区中配置 Amazon EC2 实例和 Amazon RDS MultiAZ DB 集群。
请安装 psql、git 和 docker,并创建一个新的 Docker 组,以便您可以在没有 root 权限的情况下运行容器。以下是在Amazon Linux 2023 OS 中的安装步骤:
bashsudo yum install postgresql15 docker git ysudo usermod a G docker ec2usernewgrp dockersudo systemctl enable now dockerservice
现在,您的 Amazon EC2 实例和 Amazon RDS MultiAZ DB 集群已经创建,接下来让我们访问拓扑 API 并创建 PgBouncer 容器。
使用 psql 客户端连接到写入实例,并以 rdssuperuser 身份登录该帐户是您最初创建的,通常默认为 postgres。成功登录后,请创建版本为 14 或更高版本的 rdstools 扩展。该扩展提供有关您的 Amazon RDS MultiAZ DB 集群的有用数据。使用以下 SQL 命令创建 rdstools 扩展并验证扩展版本:
sqlpostgres=gt CREATE EXTENSION IF NOT EXISTS rdstoolsCREATE EXTENSION
postgres=gt SELECT extversion FROM pgextension WHERE extname LIKE rdstools extversion
14(1 row)
检查 Amazon RDS MultiAZ DB 集群的 PostgreSQL 元数据
为了实现快速切换,我们在 Amazon RDS for PostgreSQL 中实现了元数据功能。您可以通过安装最新版本的 rdstools 扩展版本 14 或更高来访问此功能,并且满足前提条件部分中列出的支持引擎版本要求。在成功安装 rdstools 扩展后,您可以使用以下命令检查 Amazon RDS MultiAZ DB 集群中的拓扑元数据:
sqlpostgres=gt SELECT FROM rdstoolsshowtopology(pgbouncer) id endpoint port dbKGLXG75BGVIWKQT7NQ4EXAMPLE1 myclusterinstance3123456789012uswest2rdsamazonawscom 5432 dbKGLXG75BGVIWKQT7NQ4EXAMPLE2 myclusterinstance2123456789012uswest2rdsamazonawscom 5432 dbKGLXG75BGVIWKQT7NQ4EXAMPLE3 myclusterinstance1123456789012uswest2rdsamazonawscom 5432(3 rows)
每列的解析如下:
id Amazon RDS MultiAZ DB 集群中每个实例的 DBI 资源 ID。endpoint 列出 Amazon RDS MultiAZ DB 集群中每个节点的 Amazon Route 53 CNAME。port 显示 Amazon RDS MultiAZ DB 集群中每个节点侦听的端口。showtopology 函数中的参数是可选的,但建议使用。传递代理标识符可以让 Amazon RDS 跟踪当前哪些代理正在查询拓扑。这为 Amazon RDS 提供了有用的遥测数据,并对未来支持额外的代理提供了指导。
PgBouncer 利用此元数据在启动时为 Amazon RDS MultiAZ DB 集群中的所有节点预创建连接池。这确保当有新的写入者时,不需要花费时间建立新连接。此外,当节点恢复为读取备用角色时,PgBouncer 会自动自我修复,通过重新创建连接池来连接先前的写入者。
PgBouncer 补丁适用于可以返回可配置查询拓扑的任何 Amazon RDS MultiAZ DB 集群的 PostgreSQL。
新元数据在 Amazon RDS for PostgreSQL 版本 154、149、1312 或更高版本中可用。如果您现有的 Amazon RDS MultiAZ DB 集群使用这些版本,请在设置 PgBouncer 之前升级到至少 R3 版本。
设置 PgBouncer 容器
一旦您完成了前提条件,就可以创建 PgBouncer 容器并测试与 Amazon RDS MultiAZ DB 集群写入节点的连接。请遵循以下步骤:
克隆 PgBouncer 快速切换库并构建容器: bash git clone https//githubcom/awslabs/pgbouncerfastswitchovergit cd pgbouncerfastswitchover docker build f Dockerfilelocal t pgbouncer
获取写入端点,并确保可以从 EC2 实例连接到它。在本示例中,Amazon RDS MultiAZ DB 集群名称为 mycluster,返回的写入端点为 myclustercluster123456789012uswest2rdsamazonawscom。您可以使用以下 AWS CLI 命令获取集群写入端点: bash aws rds describedbclusters region=uswest2 jq DBClusters[] select(DBClusterIdentifier == mycluster) Endpoint
使用 psql 测试与写入端点的连接,并确认能够成功查询集群拓扑: bash psql h lt你的集群端点gt U lt你的用户gt postgres 密码为 testuser psql (154 server 154) SSL 连接 (协议 TLSv12 密码 ECDHERSAAES256GCMSHA384 压缩 off) 输入 help 获取帮助。
奈云加速器下载postgres=gt SELECT FROM rdstoolsshowtopology(pgbouncer) id endpoint port dbKGLXG75BGVIWKQT7NQ4EXAMPLE1 myclusterinstance3123456789012uswest2rdsamazonawscom 5432 dbKGLXG75BGVIWKQT7NQ4EXAMPLE2 myclusterinstance2123456789012uswest2rdsamazonawscom 5432 dbKGLXG75BGVIWKQT7NQ4EXAMPLE3 myclusterinstance1123456789012uswest2rdsamazonawscom 5432(3 rows)
如果连接超时,请确保您的 Amazon EC2 实例和 Amazon RDS MultiAZ DB 集群位于同一子网,或者相应调整安全组设置。有关更多信息,请查看在 VPC 中访问 DB 实例的场景以及通过安全组控制对 AWS 资源的流量。如果这些实例位于不同地区,您需要采取额外的措施。详细信息请参见什么是 VPC 对等连接?
修改 PgBouncer 配置,使其匹配您的集群写入端点和凭据。在 pgbouncerfastswitchover/pgbouncerini 文件中更新以下内容:
将 ltchangetoclusterendpointgt 更改为您的写入端点将 ltchangedbusergt 更改为您的集群用户将 ltchangedbpasswordgt 更改为集群的密码在本示例中,配置如下:
inipostgres = host=myclustercluster123456789012uswest2rdsamazonawscom port=5432 user=ltusernamegt password=ltpasswordgt dbname=postgres topologyquery=select endpoint from rdstoolsshowtopology(pgbouncer)
现在,启动容器并测试通过 PgBouncer 连接: bash docker run v (pwd)/pgbouncerini/home/pgbouncer/pgbouncerini v (pwd)/userlisttxt/home/pgbouncer/userlisttxt network host rm it pgbouncer /startsh
在新的终端窗口或标签中,测试连接到 PgBouncer。您可以从 pgbouncerfastswitchover/userlisttxt 获取默认凭据。您也可以根据需要进行更新: bash psql h localhost U testuser postgres 密码为 testuser psql (154 server 154) 输入 help 获取帮助。
postgres=gt select 1 column
1
(1 row)
测试快速切换
现在,您已经成功创建了 PgBouncer 容器并连接到 Amazon RDS MultiAZ DB 集群,接下来让我们测试快速切换。为了测量停机时间,我们包括了一个辅助 Python 脚本:
python
!/usr/bin/python3
import timeimport subprocessfrom datetime import datetime timezone
t0 = timetime()
while True ret = subprocesscall(PGPASSWORD= psql h localhost p 5432 U testuser c SELECT 1 d postgres shell=True stdout=subprocessDEVNULL) t1 = timetime() timediff = (t1 t0) 1000 if timediff gt 200 print(f自上次更新以来的时间 {timediff2f}ms) t0 = timetime()

您可以通过发出 小版本升级命令 并使用 立即应用配置 来测试切换。升级可能需要一些时间才能完成。在本示例中,我们使用 AWS CLI 进行从 154 版本升级到 155 版本。
bashaws rds modifydbcluster dbclusteridentifier mycluster engineversion 155 autominorversionupgrade applyimmediately region uswest2
在升级运行过程中,同时运行 Python 脚本并监测停机时间。在 Amazon RDS MultiAZ DB 集群中,当写入节点切换到升级后的节点时,停机时间会开始。在脚本中用毫秒来计量,在我们的示例中,停机时间为 74155ms。
bash python3 helperpy自上次更新以来的时间 74155ms
新配置选项
AWS 提供的 PgBouncer 补丁引入了一些配置选项。让我们详细了解它们。
topologyquery
topologyquery 用于在 PgBouncer 启动时获取 Amazon RDS MultiAZ DB 集群的端点。如果您希望在 Amazon RDS for PostgreSQL 之外使用快速切换,则拓扑表必须包含一个名为 endpoint 的列。每个端点都用于创建连接池。当检测到写入端点不可用时,PgBouncer 会使用 pgisinrecovery() 检查每个 endpoint 以识别新的写入者,然后恢复客户端查询。
pollingfrequency
pollingfrequency 允许您调整在切换期间 pgisinrecovery 的调用频率。默认建议值为 100 毫秒。
serverfaileddelay
serverfaileddelay 允许您修改在尝试连接 Amazon RDS MultiAZ DB 集群中的节点失败后需要等待多长时间。默认值设置为 30 秒。如果该值设置得过低,可能会减慢节点恢复的时间,因为会出现连接风暴。
recreatedisconnectedpools
在切换过程中或由于超时,连接池可能关闭。如果启用了 recreatedisconnectedpools 并且为数据库设置了 topologyquery,则 PgBouncer 会自动重新创建关闭的连接池。recreatedisconnectedpools 的默认值是启用的。
性能基准
我们创建了一个 r6gd2xlarge 实例类型的 Amazon RDS MultiAZ 集群,并运行了只读工作负载。将补丁后的 PgBouncer 与 1191 版本进行比较,性能几乎相同。
以下代码显示的是 PgBouncer 1191:
bash pgbench c 500 T 900 postgres p 5432 U test j 2 S h localhostpgbench (154 server 154)开始清理结束。事务类型 lt内置 仅选择gt缩放因子 1查询模式 简单客户端数量 500线程数 2持续时间 900s实际处理的事务数 235771