bigywater.tech
Django · 134

数据库连接池配置

Django 默认每个请求新建一条数据库连接。持久连接(CONN_MAX_AGE)和 Django 的原生连接池(OPTIONS pool)分别带来什么?它们又会在什么时候出问题?这篇在自己起的 PostgreSQL 上数连接、量延迟,再把连接数压到上限。

200 / 200
默认配置下每个请求新建一次数据库连接(预热后计数)
2.60 → 0.51 ms
请求中位延迟:新建连接 → 连接池
20 个失败
持久连接 + 40 个线程撞上 max_connections=20,连接池则全部成功

每个请求新建连接的代价

实测 · 本机执行输出
  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 事务级池化时的注意事项、服务端游标的兼容性,本文没有测。

分步演示

连接池
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Python 3.14.7 / Django 6.1.1(默认用 SQLite,其它数据库会在文中注明),用 django.test.Client 或真实的本机服务器进程实测;计时用 time.perf_counter,数字每次运行会有小幅抖动。自己起的临时 PostgreSQL 16(log_connections=on、max_connections=20、fsync=off);gunicorn 26.2.0;psycopg 3.3.6 + psycopg_pool 3.3.3;连接池 min_size 2 / max_size 4(每进程)
    • 没有验证:pgbouncer、连接池的 timeout / 健康检查、CONN_HEALTH_CHECKS、MySQL、异步视图下的连接行为(第 115 篇)、长事务占用连接的影响、生产环境的网络延迟
    京ICP备2026067502号-1京公网安备11010502063487号