Django 默认每个请求新建一条数据库连接。持久连接(CONN_MAX_AGE)和 Django 的原生连接池(OPTIONS pool)分别带来什么?它们又会在什么时候出问题?这篇在自己起的 PostgreSQL 上数连接、量延迟,再把连接数压到上限。
CONN_MAX_AGE=0(默认:每个请求新建连接) 预热 10 个请求之后,新建连接 200 次 延迟中位 2.60 ms CONN_MAX_AGE=60(持久连接) 预热 10 个请求之后,新建连接 0 次 延迟中位 0.52 ms 连接池 OPTIONS pool(min 2, max 4) 预热 10 个请求之后,新建连接 0 次 延迟中位 0.51 ms
新建连接的次数来自 PostgreSQL 日志里的 connection authorized 行(排除了 psql 自己)。本机回环、fsync 关闭,所以绝对值很小,生产环境里 TLS 与网络延迟会让这个差距更大(本文没有测)。
CONN_MAX_AGE=60(持久连接) 状态码分布 {200: 20, 500: 20} 总耗时 569 ms
连接池 OPTIONS pool(min 2, max 4) 状态码分布 {200: 40} 总耗时 3022 ms
PostgreSQL 日志里的拒绝信息(最后一条): 2026-10-01 08:34:44.675 CST [89231] FATAL: sorry, too many clients already持久连接是每个线程一条,线程数 × 进程数 就是最多需要的连接数,它必须小于数据库的 max_connections(还要给迁移、监控等留出空位)。连接池把「同时使用的连接数」和「线程数」解耦。
连接池要求 psycopg 3 加 psycopg_pool,本文只测了 CONN_MAX_AGE 与连接池各自单独使用,没有测同时设置。使用 pgbouncer 事务级池化时的注意事项、服务端游标的兼容性,本文没有测。