K8s中Django多副本连PostgreSQL/PGBouncer遇连接数耗尽问题求助
Django + PGBouncer + PostgreSQL 多副本连接问题排查与扩容疑问
问题现象
在Kubernetes环境中运行Django+PGBouncer+PostgreSQL架构的应用,单Django副本运行无异常,但启动2个副本后,部分请求触发以下错误:
Django侧报错
django.db.utils.OperationalError: ERROR: no more connections allowed (max_client_conn)
PGBouncer侧报错
1 WARNING C-0x55d76aeb6330: (nodb)/(nouser)@xx.xx.xx.xx:37002 pooler error: no more connections allowed (max_client_conn)
当前配置
PostgreSQL配置
容器启动参数设置max_connections=400,实际验证值一致:
containers: - name: acapela-cloud-database image: postgres:12.0 imagePullPolicy: Always ports: - containerPort: 5432 args: - postgres - -c - max_connections=400
执行SQL验证结果:
SHOW max_connections; max_connections ----------------- 400 (1 row)
PGBouncer配置(Kubernetes Deployment + Service)
apiVersion: apps/v1 kind: Deployment metadata: name: pgbouncer labels: app: pgbouncer spec: selector: matchLabels: app: pgbouncer template: metadata: labels: app: pgbouncer spec: containers: - name: pgbouncer image: edoburu/pgbouncer:1.9.0 imagePullPolicy: Always ports: - containerPort: 5432 env: - name: DB_HOST value: "database" - name: DB_PORT value: "5432" - name: DB_USER value: "" - name: DB_PASSWORD value: "" - name: DB_DATABASE value: "" - name: PGBOUNCER_LISTEN_PORT value: "6432" - name: PGBOUNCER_MAX_CLIENT_CONN value: "800" - name: PGBOUNCER_DEFAULT_POOL_SIZE value: "400" - name: POOL_MODE value: transaction - name: SERVER_RESET_QUERY value: DISCARD ALL livenessProbe: tcpSocket: port: 5432 periodSeconds: 60 lifecycle: preStop: exec: # Allow existing queries clients to complete within 120 seconds command: ["/bin/sh", "-c", "killall -INT pgbouncer && sleep 120"] securityContext: allowPrivilegeEscalation: false capabilities: drop: ['all'] --- apiVersion: v1 kind: Service metadata: name: pgbouncer labels: app: pgbouncer spec: type: ClusterIP ports: - port: 5432 targetPort: 5432 protocol: TCP name: pgbouncer selector: app: pgbouncer
问题解决配置调整
当前报错的核心原因是端口不匹配导致流量转发异常:
PGBouncer通过PGBOUNCER_LISTEN_PORT设置监听6432端口,但Deployment的containerPort和Service的targetPort都配置为5432,导致Kubernetes无法正确将Django的连接请求转发到PGBouncer的实际监听端口,无效连接堆积最终触发max_client_conn上限。
需要调整两处配置:
- 修改PGBouncer Deployment的容器端口:将
containerPort改为6432,与PGBOUNCER_LISTEN_PORT保持一致 - 修改PGBouncer Service的targetPort:同样改为
6432,确保流量转发到正确端口
调整后的关键配置片段:
Deployment容器端口部分
ports: - containerPort: 6432
Service端口部分
ports: - port: 5432 targetPort: 6432 protocol: TCP name: pgbouncer
同时确认Django的数据库连接配置指向PGBouncer Service的5432端口(Service的port保持5432不变)。
扩容可行性分析
问题修复后,该架构完全支持启动5/10/15甚至更多Django副本,核心依据如下:
- 连接池机制适配:采用
transaction池模式,事务结束后立即回收数据库连接并复用,避免每个Django进程长期占用独立PostgreSQL连接 - 配置匹配合理:
PGBOUNCER_DEFAULT_POOL_SIZE=400与PostgreSQL的max_connections=400完全匹配,确保PGBouncer不会向PostgreSQL发起超出上限的连接请求 - 客户端连接能力充足:
PGBOUNCER_MAX_CLIENT_CONN=800支持最多800个客户端连接,每个Django副本通常仅维护少量持久连接(默认CONN_MAX_AGE配置下每个进程最多1个),800的上限足以支撑数十个副本的连接需求
若后续副本数持续增长,可根据实际连接压力逐步上调PGBOUNCER_MAX_CLIENT_CONN(建议不超过PostgreSQLmax_connections的2-3倍,避免PGBouncer自身资源过载);同时需注意PostgreSQL的max_connections不要盲目调大,每个连接会占用内存,过高会导致数据库性能下降。
内容的提问来源于stack exchange,提问作者wzxecr
相关产品推荐
相关产品推荐

