配置RDS Proxy
- 难度等级: 中级
- 预计时长: 1-2 小时
- 适用场景: 高连接数应用、Serverless 架构、频繁连接应用
- 支持引擎: Aurora MySQL/PostgreSQL, RDS MySQL/PostgreSQL/MariaDB/SQL Server
通过部署 Amazon RDS Proxy 实现数据库连接池管理,降低数据库负载,缩短故障转移时间,并提升应用可用性。
在开始配置前,需满足以下条件:
- RDS 数据库实例或 Aurora 集群已创建
- VPC 中至少有 2 个私有子网
- 数据库安全组已配置
IAM 权限
Section titled “IAM 权限”- 具有创建 RDS Proxy 的权限
- 具有创建 Secrets Manager 密钥的权限
- 具有创建 IAM 角色的权限
- 数据库引擎为支持的版本
- 数据库必须在 VPC 内(不支持 EC2-Classic)
- 数据库不能是 RDS Custom for SQL Server
理解 RDS Proxy
Section titled “理解 RDS Proxy”什么是 RDS Proxy
Section titled “什么是 RDS Proxy”通俗类比:RDS Proxy 就像酒店前台接待员。客人(应用)不直接去找房间(数据库),而是先到前台(Proxy)登记。前台统一管理房间分配、钥匙(连接)复用,避免每位客人都要求新房间,从而提升酒店(数据库)的运营效率。
技术定义:RDS Proxy 是 AWS 托管的数据库代理服务,位于应用和数据库之间,通过连接池管理、连接复用和智能路由,优化数据库连接使用效率。
graph TB
A[应用层<br/>100个应用连接] --> B[RDS Proxy<br/>连接池]
B --> C[数据库层<br/>10个实际连接]
B --> D[连接复用]
B --> E[故障转移]
B --> F[IAM认证]
style A fill:#e1f5ff
style B fill:#fff4e1
style C fill:#e1ffe1
核心机制:
- 连接池:Proxy 维护一个到数据库的连接池,多个应用连接共享少量数据库连接
- 连接复用:应用关闭连接后,Proxy 保持数据库连接活跃并分配给新请求
- 智能路由:故障时自动切换到备用实例,保持应用连接不中断
步骤 1: 评估是否需要 RDS Proxy
Section titled “步骤 1: 评估是否需要 RDS Proxy”强烈推荐使用:
-
Serverless 应用(Lambda 函数)
- 问题:Lambda 并发执行时产生大量短生命周期连接
- 解决:Proxy 的连接池避免数据库连接数耗尽
-
高频连接应用
- 问题:PHP、Ruby on Rails 等框架频繁打开/关闭连接
- 解决:连接复用减少数据库 CPU 和内存开销
-
突发流量应用
- 问题:电商促销、SaaS 应用流量激增导致连接数超限
- 解决:连接池管控和限流保护数据库
-
长连接空闲应用
- 问题:保持大量空闲连接占用数据库资源
- 解决:Proxy 管理空闲连接,释放数据库资源
可选使用:
- 需要集中管理数据库凭证
- 需要强制 IAM 认证
- 需要缩短故障转移时间(减少 66%)
不适合使用:
- 应用已有成熟的连接池管理
- 连接数始终保持较低水平(< 20)
- 使用不支持的数据库引擎或特性
通过 CloudWatch 监控判断:
| 指标 | 阈值 | 说明 |
|---|---|---|
DatabaseConnections | 接近 max_connections 的 80% | 连接数压力大 |
ConnectionAttempts | 高频率 | 频繁建立新连接 |
| CPU 利用率 | > 70% | 可能由连接开销导致 |
| T2/T3 实例内存 | 频繁接近上限 | 小实例连接开销大 |
步骤 2: 创建 Secrets Manager 密钥
Section titled “步骤 2: 创建 Secrets Manager 密钥”为什么需要 Secrets Manager
Section titled “为什么需要 Secrets Manager”RDS Proxy 通过 Secrets Manager 安全存储和获取数据库凭证,实现:
- 凭证集中管理
- 自动轮换密码
- 加密存储
- IAM 权限控制
创建密钥步骤
Section titled “创建密钥步骤”控制台操作:
- 打开 AWS Secrets Manager 控制台
- 选择”存储新的密钥”
- 密钥类型:选择”RDS 数据库的凭证”
- 配置参数:
用户名: 数据库管理员用户(如 admin)密码: 数据库密码加密密钥: 使用默认 KMS 密钥或自定义选择数据库: 选择目标 RDS 实例或 Aurora 集群
- 密钥名称:
rds-proxy-secret-{database-name} - 轮换配置:建议启用自动轮换(可选)
最佳实践:
- 为每个数据库用户创建独立密钥
- 对于多租户应用,可创建最多 200 个密钥(Proxy 限制)
- 密钥名称使用清晰命名规范
[创建Secrets Manager密钥]
步骤 3: 创建 IAM 角色
Section titled “步骤 3: 创建 IAM 角色”配置 IAM 角色
Section titled “配置 IAM 角色”RDS Proxy 需要 IAM 角色来访问 Secrets Manager:
信任策略:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "rds.amazonaws.com" }, "Action": "sts:AssumeRole" } ]}权限策略:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue" ], "Resource": "arn:aws:secretsmanager:region:account-id:secret:secret-name" }, { "Effect": "Allow", "Action": [ "kms:Decrypt" ], "Resource": "arn:aws:kms:region:account-id:key/key-id", "Condition": { "StringEquals": { "kms:ViaService": "secretsmanager.region.amazonaws.com" } } } ]}角色命名建议:rds-proxy-role-{database-name}
[创建IAM角色]
步骤 4: 创建 RDS Proxy
Section titled “步骤 4: 创建 RDS Proxy”控制台路径:RDS 控制台 → Proxies → Create proxy
必填参数:
代理标识符: my-rds-proxy引擎系列: 选择数据库引擎(MySQL/PostgreSQL)目标数据库: 选择 RDS 实例或 Aurora 集群VPC 和子网:
- VPC:必须与数据库在同一 VPC
- 子网:选择至少 2 个不同可用区的私有子网
- 最佳实践:选择与数据库相同的子网组
安全组:
- 创建新安全组或选择现有
- 入站规则:允许应用安全组访问(端口 3306/5432)
- 出站规则:允许访问数据库安全组(端口 3306/5432)
身份验证配置
Section titled “身份验证配置”IAM 角色:选择步骤 3 创建的角色
密钥配置:
- 添加步骤 2 创建的 Secrets Manager 密钥
- 可添加多个密钥支持不同数据库用户
- IAM 身份验证:可选启用(推荐用于 Lambda)
关键参数:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 最大连接百分比 | 75% | 占数据库 max_connections 的百分比 |
| 最大空闲连接百分比 | 50% | 保持活跃的最小连接数 |
| 连接借用超时 | 120 秒 | 等待可用连接的最长时间 |
| 空闲客户端连接超时 | 1800 秒 | 应用空闲连接关闭时间 |
为什么这样配置:
- 75% 最大连接:为直接连接和运维操作预留 25% 容量
- 1800 秒超时:平衡资源释放和连接复用效率
会话固定过滤器
Section titled “会话固定过滤器”Session Pinning Filters:某些数据库操作会导致连接”固定”到特定实例,降低连接池效率。
推荐配置:保持默认(None),除非遇到以下场景:
EXCLUDE_VARIABLE_SETS:排除设置会话变量的操作- 使用临时表、预处理语句时需评估影响
最佳实践:初期不配置过滤器,通过 CloudWatch 监控 DatabaseConnectionsCurrentlySessionPinned 指标,如持续偏高再调整。
[创建RDS Proxy配置]
步骤 5: 配置读写分离(重要)
Section titled “步骤 5: 配置读写分离(重要)”AWS 没有自动读写分离
Section titled “AWS 没有自动读写分离”关键认知:RDS Proxy 默认端点不会自动区分读写请求,所有流量都路由到写入实例。要实现读写分离,必须手动配置。
理解 Proxy 端点类型
Section titled “理解 Proxy 端点类型”| 端点类型 | 路由目标 | 用途 |
|---|---|---|
| 默认端点(Read/Write) | 写入实例 | 所有读写操作 |
| 只读端点(Read-Only) | 只读副本 | 仅查询操作 |
重要说明:Proxy 不会分析 SQL 语句类型(SELECT/INSERT),需要应用层区分读写请求。
创建只读端点
Section titled “创建只读端点”前提条件:
- Aurora 集群至少有 1 个 Reader 实例,或
- RDS Multi-AZ 集群至少有 1 个 Reader 实例
创建步骤:
- 进入 Proxy 详情页
- Proxy endpoints → Create endpoint
- 配置参数:
端点名称: my-rds-proxy-readonly目标角色: Read-onlyVPC: 与 Proxy 相同
- 记录端点地址:
my-rds-proxy-readonly.proxy-xxx.region.rds.amazonaws.com
[创建只读端点]
应用层实现读写分离
Section titled “应用层实现读写分离”方案 1:使用双连接池(推荐)
# Python 示例from sqlalchemy import create_engine
# 写连接 - 连接到默认端点write_engine = create_engine( 'mysql://user:pass@my-rds-proxy.proxy-xxx.region.rds.amazonaws.com:3306/db')
# 读连接 - 连接到只读端点read_engine = create_engine( 'mysql://user:pass@my-rds-proxy-readonly.proxy-xxx.region.rds.amazonaws.com:3306/db')
# 应用中区分使用def create_order(data): with write_engine.connect() as conn: conn.execute("INSERT INTO orders VALUES (...)")
def get_order(order_id): with read_engine.connect() as conn: return conn.execute("SELECT * FROM orders WHERE id = ?", order_id)方案 2:使用 ORM 的读写分离功能
Spring Boot 示例:
@Transactional(readOnly = false) // 使用写端点public void createOrder(Order order) { orderRepository.save(order);}
@Transactional(readOnly = true) // 使用读端点public Order getOrder(Long id) { return orderRepository.findById(id);}方案 3:使用第三方代理(不推荐)
对于需要自动 SQL 分析的场景,可使用:
- ProxySQL(开源,需自行部署和维护)
- Heimdall Proxy(第三方商业产品)
为什么不推荐:增加额外组件复杂度、维护成本和故障点。应用层读写分离更清晰可控。
配置最佳实践
Section titled “配置最佳实践”连接字符串管理:
环境变量方式: DB_WRITE_HOST=my-rds-proxy.proxy-xxx.region.rds.amazonaws.com DB_READ_HOST=my-rds-proxy-readonly.proxy-xxx.region.rds.amazonaws.com DB_PORT=3306 DB_NAME=mydb连接池配置建议:
写连接池: - 最小连接数: 5 - 最大连接数: 20 - 连接超时: 30s
读连接池: - 最小连接数: 10 - 最大连接数: 50 - 连接超时: 30s为什么读连接池更大:通常读操作占 70-80%,需更多连接满足查询需求。
步骤 6: 更新应用连接配置
Section titled “步骤 6: 更新应用连接配置”修改连接字符串
Section titled “修改连接字符串”从直连数据库改为通过 Proxy:
原连接字符串: mysql://user:pass@mydb.xxx.region.rds.amazonaws.com:3306/database
新连接字符串(写操作): mysql://user:pass@my-rds-proxy.proxy-xxx.region.rds.amazonaws.com:3306/database
新连接字符串(读操作): mysql://user:pass@my-rds-proxy-readonly.proxy-xxx.region.rds.amazonaws.com:3306/databaseLambda 函数配置
Section titled “Lambda 函数配置”使用 IAM 认证(推荐):
import boto3import pymysql
def get_db_connection(): client = boto3.client('rds') token = client.generate_db_auth_token( DBHostname='my-rds-proxy.proxy-xxx.region.rds.amazonaws.com', Port=3306, DBUsername='iam_user' )
connection = pymysql.connect( host='my-rds-proxy.proxy-xxx.region.rds.amazonaws.com', user='iam_user', password=token, database='mydb', ssl={'ca': '/path/to/rds-ca-bundle.pem'} ) return connection为什么使用 IAM 认证:
- 无需在代码中存储密码
- 自动令牌轮换(15 分钟有效期)
- 使用 Lambda 执行角色权限
VPC 配置要求
Section titled “VPC 配置要求”Lambda 函数必须配置:
- VPC:与 Proxy 相同的 VPC
- 子网:私有子网
- 安全组:允许访问 Proxy 安全组
[更新应用连接配置]
步骤 7: 监控和优化
Section titled “步骤 7: 监控和优化”关键监控指标
Section titled “关键监控指标”CloudWatch 指标:
| 指标 | 正常范围 | 异常处理 |
|---|---|---|
DatabaseConnections | < 最大连接数的 75% | 增加 Reader 实例 |
DatabaseConnectionsCurrentlyBorrowed | - | 活跃连接数,用于容量规划 |
DatabaseConnectionsCurrentlySessionPinned | < 10% | 优化应用代码减少固定 |
ClientConnections | - | 应用端连接总数 |
QueryDatabaseResponseLatency | < 50ms | 数据库性能问题 |
告警配置建议:
DatabaseConnectionsCurrentlySessionPinned > 20%: 问题:连接池效率低 原因:频繁使用临时表、预处理语句、SET 变量 解决:优化应用代码或配置会话固定过滤器
ClientConnections 突增: 问题:应用突发流量 解决:检查 Proxy 是否正常限流保护数据库评估连接池配置是否合理:
- 观察
DatabaseConnections是否接近配置的最大值 - 观察
ClientConnections与DatabaseConnections的比例 - 理想比例:10:1 到 20:1(取决于应用特性)
调整建议:
场景 1:DatabaseConnections 经常达到上限 → 增加最大连接百分比(75% → 85%) → 或增加 Reader 实例
场景 2:ClientConnections 很高但 DatabaseConnections 很低 → 说明连接池工作良好,无需调整
场景 3:SessionPinned 比例高 → 应用代码优化或启用会话固定过滤器Proxy 计费方式:按数据库实例的 vCPU 小时计费
成本示例:
db.r5.large(2 vCPU): Proxy 费用 ≈ $0.015/vCPU/小时 × 2 × 730小时 = $21.9/月
db.r5.xlarge(4 vCPU): Proxy 费用 ≈ $0.015/vCPU/小时 × 4 × 730小时 = $43.8/月优化建议:
- 仅对需要连接池的数据库启用 Proxy
- 开发测试环境可不启用
- 评估 Proxy 带来的成本节约(减少数据库规格、避免连接数扩容)
[监控仪表板配置]
1. 连接池管理(核心价值)
- 减少数据库连接开销(CPU、内存)
- 允许应用打开数千连接但数据库只维护数百连接
- 小实例(T2/T3)受益最大
2. 提升可用性
- 故障转移时间缩短 66%(从 60 秒降至 20 秒)
- 应用连接在故障转移期间保持,无需重连
- Multi-AZ 部署确保 Proxy 自身高可用
3. 增强安全性
- 集中管理数据库凭证(Secrets Manager)
- 强制 IAM 认证
- TLS 1.3 加密(即使数据库仅支持旧版本)
4. 无需修改应用代码
- 仅更改连接字符串
- 与数据库协议完全兼容
1. 不支持的功能
- 不支持 RDS Custom for SQL Server
- 不支持公开访问(必须在 VPC 内)
- MySQL:不支持某些认证插件
- PostgreSQL:不支持取消查询(Ctrl+C)
2. 配额限制
- 每账号默认 20 个 Proxy(可申请增加)
- 每个 Proxy 最多 200 个 Secrets Manager 密钥
- 每个 Proxy 最多 20 个端点
3. 会话固定问题
- 使用临时表、预处理语句、SET 变量会导致连接固定
- 固定期间连接无法被其他请求复用
- 影响连接池效率
4. 不支持某些数据库特性
- SQL Server:不支持 Active Directory 认证
- MySQL:
@@IDENTITY、@@ROWCOUNT可能不准确 - PostgreSQL:默认
postgres数据库不能删除
何时使用 RDS Proxy
Section titled “何时使用 RDS Proxy”最佳实践决策树:
是否使用 Lambda 或容器化应用? ├─ 是 → 强烈推荐使用 Proxy └─ 否 → 继续判断
应用是否频繁打开/关闭连接? ├─ 是(如 PHP/Ruby on Rails)→ 推荐使用 └─ 否 → 继续判断
数据库连接数是否接近上限? ├─ 是 → 推荐使用 └─ 否 → 可选
是否需要缩短故障转移时间? ├─ 是 → 推荐使用 └─ 否 → 评估成本后决定读写分离实施建议
Section titled “读写分离实施建议”推荐方案排序:
-
应用层双连接池(首选)
- 优点:逻辑清晰、可控性强、易于调试
- 缺点:需要少量代码改动
- 适用:所有新项目和可改造项目
-
ORM 框架的 @Transactional(readOnly)(次选)
- 优点:框架级支持、代码侵入小
- 缺点:依赖框架能力
- 适用:Spring、Django、Rails 等
-
第三方代理 SQL 解析(不推荐)
- 优点:应用无需改动
- 缺点:额外维护成本、故障点、学习曲线
- 适用:遗留系统且完全无法修改代码
部署最佳实践
Section titled “部署最佳实践”阶段化部署:
阶段 1:非生产环境验证 - 创建 Proxy 连接到开发/测试数据库 - 应用完整功能测试 - 性能基准测试 - 监控指标观察
阶段 2:生产环境灰度 - 选择 10% 流量切换到 Proxy - 观察 1 周监控指标 - 逐步增加到 50%、100%
阶段 3:优化调整 - 根据 SessionPinned 指标优化代码 - 调整连接池参数 - 配置告警规则回退方案:
- 保留原数据库直连端点
- 通过配置中心快速切换连接字符串
- 监控关键业务指标确保无异常
跨 VPC 访问:
使用场景:应用和数据库在不同 VPC
graph LR
A[应用 VPC] --> B[Proxy 跨VPC端点]
B --> C[数据库 VPC]
style A fill:#e1f5ff
style B fill:#fff4e1
style C fill:#e1ffe1
配置步骤:
- 创建额外的 Proxy 端点
- 选择应用 VPC 和子网
- 配置安全组允许跨 VPC 访问
- 应用连接到跨 VPC 端点
为什么不用 VPC Peering:Proxy 跨 VPC 端点使用 PrivateLink,配置更简单且更安全。
Q1: RDS Proxy 会增加延迟吗?
A: 会有轻微延迟增加(通常 < 1ms)。但连接复用带来的整体性能提升远超过这点延迟。对于高频建立连接的应用,整体响应时间反而会下降。
Q2: 使用 Proxy 后如何直接连接数据库进行运维?
A: 保留原数据库端点用于直接连接。运维操作(如执行 DDL、数据导入)建议直连数据库,避免受 Proxy 连接池限制。
Q3: Proxy 是否支持数据库参数修改?
A: 支持,但数据库参数修改需要重启实例才能被 Proxy 识别,即使选择”立即应用”。集群级参数需要集群范围重启。
Q4: 如何验证应用是否通过 Proxy 连接?
A: 查看 CloudWatch 指标 ClientConnections,或在数据库中执行:
-- MySQLSELECT user, host FROM information_schema.processlist;-- 通过 Proxy 的连接会显示 Proxy 的内部 IP
-- PostgreSQLSELECT usename, client_addr FROM pg_stat_activity;Q5: 使用 Proxy 后还需要应用层连接池吗?
A: 需要。应用层连接池管理到 Proxy 的连接,Proxy 管理到数据库的连接。两层连接池配合使用效果最佳。
Q6: Proxy 默认端点是否会自动读写分离?
A: 不会。这是常见误解。默认端点所有请求都路由到写入实例。必须创建只读端点并在应用层区分读写请求才能实现读写分离。
Q7: 如何处理复杂事务中的读写混合?
A: 整个事务使用写端点。示例:
# 错误做法with read_engine.begin(): # 使用只读端点 data = conn.execute("SELECT * FROM accounts WHERE id = 1") conn.execute("UPDATE accounts SET balance = ... WHERE id = 1") # 失败!
# 正确做法with write_engine.begin(): # 整个事务使用写端点 data = conn.execute("SELECT * FROM accounts WHERE id = 1 FOR UPDATE") conn.execute("UPDATE accounts SET balance = ... WHERE id = 1")Q8: Proxy 费用如何计算?
A: 按数据库实例 vCPU 计费,与实例运行时间相同。如果 Proxy 连接到 Aurora 集群(1 个 Writer + 2 个 Reader),按所有实例的总 vCPU 计费。
- 评估应用是否适合使用 Proxy
- 确认数据库引擎和版本支持
- VPC 至少有 2 个私有子网(不同 AZ)
- 创建 Secrets Manager 密钥
- 创建 IAM 角色并配置权限
- 规划安全组规则
- Proxy 状态为”Available”
- 通过 Proxy 端点可正常连接数据库
- 应用功能测试通过
- 只读端点已创建(如需要)
- CloudWatch 监控指标正常
- 配置告警规则
- 文档记录端点地址和配置
读写分离检查
Section titled “读写分离检查”- 已创建只读端点
- 应用代码区分读写请求
- 读连接池指向只读端点
- 写连接池指向默认端点
- 验证只读端点流量分布到 Reader 实例
- 测试故障转移场景