You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

高并发Web压测下PostgreSQL 5432端口连接异常排查求助

高并发下Django连接PostgreSQL报错“Cannot assign requested address”排查方案

环境信息

  • Django 4.1.3
  • DRF 3.14.0
  • psycopg2 2.9.5
  • PostgreSQL 14.7
  • Gunicorn 21.2.0
  • Eventlet 0.33.3

问题背景

压测用的HealthCheckView每次请求都会触发一次数据库查询:

class HealthCheckView(APIView):
    def get(self, request, *args, **kwargs):
        try:
            Role.objects.filter().count()
        except Exception as e:
            return Response(status=499)
        return Response(status=status.HTTP_200_OK)

Gunicorn启动配置:

bind = f'0.0.0.0:{GUNICORN_PORT}'
worker_class = 'eventlet'
workers = 6

压测命令:

ab -n 10000 -c 500 https://10.30.7.7/api/v1/healthz/

当并发数超过500时,出现数据库连接错误:

django.db.utils.OperationalError: could not connect to server: Cannot assign requested address
Is the server running on host "10.30.7.7" and accepting
TCP/IP connections on port 5432?

PostgreSQL核心配置:

max_connections = 4096
shared_buffers = 16GB
effective_cache_size = 48GB
maintenance_work_mem = 2GB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 4
effective_io_concurrency = 2
work_mem = 1MB
huge_pages = try
min_wal_size = 1GB
max_wal_size = 4GB
max_worker_processes = 20
max_parallel_workers_per_gather = 4
max_parallel_workers = 20
max_parallel_maintenance_workers = 4

排查步骤

1. 排查客户端本地端口耗尽问题

报错Cannot assign requested address最常见的原因是Web服务器所在机器的本地TCP端口被耗尽:高并发下,大量短连接(每次请求新建DB连接,请求结束后断开)会进入TIME_WAIT状态,占用端口无法快速复用。

  • 检查当前TIME_WAIT连接数量:
    netstat -antp | grep TIME_WAIT | wc -l
    # 或用更高效的ss命令
    ss -s | grep TIME-WAIT
    
  • 调整内核参数优化端口复用(临时生效,需写入/etc/sysctl.conf永久生效):
    # 允许复用TIME_WAIT状态的端口
    net.ipv4.tcp_tw_reuse = 1
    # 扩大本地端口范围(默认可能是32768-60999)
    net.ipv4.ip_local_port_range = 1024 65535
    # 提高TCP监听队列上限
    net.core.somaxconn = 2048
    # 缩短TIME_WAIT超时时间(默认60s,可调整为30s)
    net.ipv4.tcp_fin_timeout = 30
    
    执行sysctl -p使配置生效。

2. 配置Django数据库连接池,避免重复创建连接

Eventlet是协程模型,默认每个协程会新建一个数据库连接,高并发下会产生大量短连接。启用连接池可以复用连接,减少端口占用:

修改Django的settings.py数据库配置,使用psycopg2内置连接池:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'your_db_name',
        'USER': 'your_db_user',
        'PASSWORD': 'your_db_pwd',
        'HOST': '10.30.7.7',
        'PORT': '5432',
        # 连接复用时长(秒)
        'CONN_MAX_AGE': 60,
        'OPTIONS': {
            # 连接池大小(根据worker数调整,6个worker建议每个分配20-30个连接)
            'pool_size': 20,
            # 超出池大小的临时连接数
            'max_overflow': 10,
            # 连接空闲超时时间
            'connect_timeout': 5,
        }
    }
}

注意:确保Eventlet对psycopg2打了补丁,在wsgi.py中添加:

import eventlet
eventlet.monkey_patch()

3. 调整Gunicorn的协程并发参数

Eventlet worker的worker_connections参数控制每个worker能处理的最大协程数(默认1000),过高的协程数会导致大量DB连接请求。结合连接池配置,合理调整该参数:

修改gunicorn.conf.py:

bind = f'0.0.0.0:{GUNICORN_PORT}'
worker_class = 'eventlet'
workers = 6
# 每个worker的最大协程数,建议不超过数据库连接池总容量(6*20=120,可设置为200)
worker_connections = 200

4. 验证PostgreSQL连接数及系统限制

虽然配置了max_connections=4096,但需确认实际生效情况,同时检查系统进程数限制:

  • 登录PostgreSQL执行:
    show max_connections;
    show listen_addresses; -- 确认允许10.30.7.7连接
    
  • 检查PostgreSQL运行用户的进程数限制:
    ulimit -u -p postgres
    
    若进程数小于max_connections,需修改/etc/security/limits.conf:
    postgres soft nproc 65535
    postgres hard nproc 65535
    

5. 排查网络层限制

  • 检查防火墙(iptables/ufw)是否对TCP连接数做了限制:
    iptables -L -n | grep LIMIT
    
  • 若存在负载均衡或反向代理,检查其连接数上限配置(如Nginx的worker_connections)。

内容的提问来源于stack exchange,提问作者fffxxx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 17:43:20