部署到Heroku的Django API出现PostgreSQL连接槽预留错误如何解决?
错误触发原因
- Heroku PostgreSQL实例有固定的连接数硬上限,不同档位套餐上限不同,最低配的Hobby Dev实例仅支持最多20个并发连接。当普通用户占用的连接数达到上限后,剩下的连接槽位仅预留供超级用户使用,普通业务请求就会抛出该错误。
- 调整
conn_max_age后问题未解决甚至加重,是因为该参数控制Django长连接的存活时长,调高后空闲连接会被持有更久,反而会占用连接槽位,加剧连接耗尽的问题。 - 多进程部署架构下连接数超额:如果用Gunicorn、Uvicorn等多Worker部署服务,每个Worker会维护独立的数据库连接池,总连接数=Worker数 * 单Worker连接池上限,很容易超出实例的连接数上限。
- 存在连接泄漏:异常退出的请求、未正确关闭的自定义数据库游标、长耗时异步任务持有连接未释放、僵尸进程残留的连接等,都会不断累积占用连接槽位。
- 近期业务流量上涨,并发请求量上升,合法的连接需求已经超出当前数据库实例的连接数上限。
排查修复方案
- 第一步:确认当前连接占用情况
执行heroku pg:psql命令连接到你的Heroku PostgreSQL实例,执行以下SQL确认连接情况:
查看当前普通用户占用的连接数:SELECT count(*) FROM pg_stat_activity WHERE usename = '你的数据库用户名';
查看实例的最大连接数上限:SELECT current_setting('max_connections'); - 第二步:优化Django数据库配置
调低conn_max_age参数,建议设置为30~60秒,让空闲连接可以更快释放:
限制服务Worker数量:最低配Hobby实例建议Worker数不超过2,避免单Worker连接池累加后超出总上限。如果使用连接池插件,需主动限制单Worker的最大连接数,确保总连接数不超过实例上限。DATABASES = { 'default': { # 其他数据库配置 'CONN_MAX_AGE': 60, } } - 第三步:清理僵尸连接
可以手动终止空闲超过5分钟的无效连接,执行SQL:SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE usename = '你的数据库用户名' AND state = 'idle' AND state_change < NOW() - INTERVAL '5 minutes';
也可以直接在Heroku后台重启PostgreSQL实例,临时释放所有占用的连接。 - 第四步:排查连接泄漏点
检查业务代码中是否存在以下问题:自定义数据库游标使用后未关闭、Celery等异步任务执行完未主动释放连接、长耗时接口持有数据库连接时间过长、未提交/回滚的事务长期占用连接,修复对应问题。 - 第五步:升级实例规格
如果确认是业务流量上涨导致的合法连接需求超出上限,升级Heroku PostgreSQL到更高档位的套餐,获取更高的连接数上限。
内容的提问来源于stack exchange,提问作者Babayega
相关产品推荐
相关产品推荐

