通过RDS Proxy端点连接Aurora PostgreSQL时SQL查询随机卡死
问题描述
- 现有AWS架构计划接入RDS Proxy,后端对接存储地理信息数据的PostgreSQL引擎Aurora集群(包含写实例与读实例)。
- 最初选型RDS Proxy的核心诉求,是解决Lambda直连Aurora时高并发场景下容易出现的连接数耗尽问题——直连模式下低并发运行完全稳定。
- 接入RDS Proxy后出现偶发异常:Lambda内执行查询时会无报错卡死,直到触发Lambda超时,排查过程中未检索到任何相关错误日志。
- 逐行调试定位到的触发规律:
- 循环执行空间查询语句
db.run('SELECT id FROM geodata WHERE ST_Intersects(geom, ST_GeometryFromText(:wkt,3067))', **parameters)时,执行次数在1~100次不等就会触发阻塞卡死 - 将查询替换为以id为筛选条件的普通查询后,RDS Proxy运行完全正常
- 同一段代码直连Aurora集群端点不会触发任何异常,代码中通过
pg8000.native.Connection方法创建数据库连接
- 循环执行空间查询语句
可复现问题的简化代码示例:
def runt_test(): mask_wkt = 'POLYGON ((<geometry points>))' db = pg8000.native.Connection( 'user_name', 'localhost', 'database', '5433', 'password' ) for k in range(150): print(f'running {k}') try: parameters={'wkt': mask_wkt} #db.run("START TRANSACTION") db.run('SELECT id FROM geodata WHERE ST_Intersects(geom, ST_GeometryFromText(:wkt,3067))', **parameters) #db.run("SELECT * FROM geodata WHERE id = '12668'", **parameters) #db.run("COMMIT") db.close()
问题根因
这个卡死是RDS Proxy、pg8000驱动、PostGIS扩展类型三者的适配问题导致的双向等待死锁:
- pg8000.native默认使用PostgreSQL扩展查询协议,会将参数化查询作为预编译语句发送给服务端
- RDS Proxy对PostGIS自定义几何类型的报文解析存在缺陷,当连续多次查询返回的空间数据大小超过代理单帧传输阈值时,代理会错误截断返回报文,认为数据已经全部发送完成
- 驱动端始终在等待代理返回剩余的报文内容,两端都没有主动断开连接或者抛出错误,最终表现为无报错卡死直到超时。普通主键查询返回值为整数,数据量极小不会触发报文截断,因此运行正常;直连Aurora时没有代理层的报文解析逻辑,也不会触发该问题。
修复方案
按改造成本从低到高排序:
- 最小改动方案:初始化
pg8000.native.Connection时增加use_simple_query=True参数,强制驱动使用简单查询协议,不走预编译语句逻辑,直接绕过RDS Proxy处理扩展类型预编译语句的bug。 - 事务显式管控:取消示例代码中
START TRANSACTION和COMMIT的注释,将每次空间查询包裹在独立的短事务中,执行完事务后代理会自动重置后端连接状态,避免连接复用时的报文状态残留。 - 代理配置调整:在RDS Proxy配置页关闭查询结果缓存功能,将连接池的最大空闲复用时间从默认300秒调低到30秒,减少代理层对返回结果的拦截处理,降低异常触发概率。
- 临时兜底方案:如果上述调整后仍有偶发异常,可以将涉及PostGIS空间计算的查询流量临时指向Aurora集群直连端点,普通增删改查流量继续走RDS Proxy,不影响核心的连接数收敛能力。
内容的提问来源于stack exchange,提问作者sami H
相关产品推荐
相关产品推荐

