Django多租户应用出现FATAL: too many clients already问题求助
排查PostgreSQL "too many clients already" 错误(多租户Django环境)
问题概述
- 触发错误:
FATAL: sorry, too many clients already - 触发特征:仅每日特定时段出现,非持续报错
- 使用架构:Django + django_tenants多租户,PostgreSQL数据库
- 当前数据库配置:
DATABASE_URL = os.environ.get('DATABASE_URL') DATABASES = {'default': dj_database_url.parse(DATABASE_URL)} DATABASES['default']['ATOMIC_REQUESTS'] = True DATABASES['default']['ENGINE'] = 'django_tenants.postgresql_backend' DATABASES['default']['CONN_MAX_AGE'] = 300 DATABASES['default']['OPTIONS'] = {'MAX_CONNS': 25} DATABASE_ROUTERS = ( 'django_tenants.routers.TenantSyncRouter', )
- 核心困惑:数据库全局
max_connections为1708,但连接数仅到400就触发错误;新增的CONN_MAX_AGE和MAX_CONNS配置怀疑未作用于租户连接。
可能原因与排查方向
1. 数据库用户级连接限制
PostgreSQL的max_connections是全局上限,但每个数据库用户可单独设置connection limit,如果应用使用的数据库用户被限制了连接数(比如400),就会触发该错误,和全局上限无关。
- 排查命令:
-- 查看当前用户的连接限制 SHOW ROLE CONNECTION LIMIT; -- 查看所有角色的连接限制 SELECT rolname, rolconnlimit FROM pg_roles;
2. django_tenants的连接池隔离机制
django_tenants多租户架构下,可能为每个租户维护独立连接池,而非共享全局连接池。你配置的MAX_CONNS=25如果是单租户连接池大小,当租户数量较多时,总连接数会是租户数 × 单租户连接数,很快突破400。
- 确认方式:查看django_tenants文档确认连接池是否按租户隔离;用
pg_stat_activity查询连接对应的租户(可通过应用进程、查询语句中的租户标识判断)。
3. 长连接(CONN_MAX_AGE)导致连接累积
CONN_MAX_AGE=300设置连接存活时间为5分钟,高峰时段创建的长连接会在5分钟内持续占用,若高峰请求量突增,短时间内连接数会快速累积到阈值。
- 排查:高峰时段执行
SELECT count(*) FROM pg_stat_activity WHERE usename='你的数据库用户';,观察连接数变化;对比请求量日志,确认连接数增长和请求量的关联。
4. 连接泄漏
开启ATOMIC_REQUESTS=True后,若请求处理中出现异常,可能导致连接未正确释放回连接池;或者代码中手动创建数据库连接但未关闭,造成连接泄漏。
- 排查:查看
pg_stat_activity中state为idle in transaction的连接数量,这类连接属于未正确提交/回滚的事务连接,会持续占用资源。
5. MAX_CONNS配置未生效或作用范围错误
你新增的OPTIONS={'MAX_CONNS':25}可能未被django_tenants的数据库引擎正确识别,或者该配置是单进程的连接池大小,若应用部署了多个进程(比如uWSGI多worker),总连接池大小会是进程数 × 25,容易突破400。
- 确认:检查Django版本和django_tenants版本,确认
MAX_CONNS配置是否兼容;查看应用进程数量,计算总连接池上限。
解决方案建议
- 若存在用户级连接限制:调整对应角色的
rolconnlimit,比如ALTER ROLE your_user CONNECTION LIMIT 1000;(根据实际需求设置)。 - 针对租户连接池隔离:调整单租户连接池大小,或限制同时活跃的租户数量;若django_tenants支持全局共享连接池,开启该配置。
- 优化长连接:根据业务高峰持续时间,适当缩短
CONN_MAX_AGE(比如设为120秒),或使用连接池自动回收闲置连接的机制。 - 修复连接泄漏:检查异常处理逻辑,确保事务正确提交/回滚;避免手动创建连接后未关闭,使用Django内置的连接管理方法。
- 调整连接池大小:结合应用进程数、租户数量,计算合理的
MAX_CONNS值,确保总连接数不超过数据库用户/全局的连接限制。
内容的提问来源于stack exchange,提问作者Pedro Henrique Coimbra e Silva
相关产品推荐
相关产品推荐

