为何Amazon Aurora(Postgres)RDS集群将所有连接导向单个只读实例?
核心原因分析
连接池复用+单次DNS解析
绝大多数数据库连接池(如HikariCP、Tomcat JDBC Pool)会复用已建立的连接,不会为每个新请求重新解析DNS。Aurora的reader端点依赖DNS轮询分发流量,但如果连接池初始化时仅做了一次DNS解析,后续所有新连接都会复用该IP对应的实例,导致全部30个连接集中在同一个只读节点。DNS缓存未及时更新
应用服务器或操作系统的DNS缓存会保留第一次解析reader端点得到的IP。虽然Aurora reader端点默认DNS TTL是5秒,但很多系统(比如Java应用默认DNS缓存为永久有效,直到重启)会强制延长缓存时间,导致缓存过期前不会重新查询DNS,新连接始终指向同一实例。连接池初始化策略问题
如果连接池的minimumIdle参数值等于maximumPoolSize(比如都设为30),连接池会在启动阶段一次性创建所有30个连接,这些连接均基于第一次DNS解析的IP,后续不会再生成新连接分配到其他实例。只读实例权重配置异常
Aurora支持为只读实例设置自定义权重(默认值为1),如果某个实例被设置了更高的权重值,DNS轮询会优先返回该实例的IP,导致连接大量集中。
对应解决思路
配置连接池定期重建连接
给连接池设置合理的maxLifetime参数(比如设为30秒),强制旧连接到期后关闭并重建。每次重建连接时,应用会重新解析reader端点的DNS,获取不同的实例IP,实现连接均匀分配。例如HikariCP的配置:hikari.maxLifetime=30000缩短DNS缓存时长
在应用层面调整DNS缓存规则,比如Java应用添加系统属性:System.setProperty("networkaddress.cache.ttl", "5"); System.setProperty("networkaddress.cache.negative.ttl", "5");操作系统层面也可调整DNS缓存(如Linux修改
/etc/resolv.conf,添加options timeout:1 attempts:1 rotate),确保DNS解析能及时更新。调整连接池空闲/最大连接数配置
将minimumIdle设置为小于maximumPoolSize的值(比如minimumIdle=10,maximumPoolSize=30),让连接池在流量增加时动态创建新连接,而不是一次性初始化所有连接。新创建的连接会重新解析DNS,分配到不同的只读实例。检查并重置实例权重
登录AWS控制台,进入Aurora集群的只读实例配置页面,确认所有实例的权重均为默认值1,避免因权重差异导致的流量倾斜。
内容的提问来源于stack exchange,提问作者clay

