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

高负载下PostgreSQL连接报错Cannot assign requested address求助

问题分析与解决方案

首先明确:这个Cannot assign requested address错误不是PostgreSQL连接数耗尽,而是你的Docker容器作为客户端,本地可用的TCP端口被耗尽了——高负载下后台脚本频繁创建、销毁数据库连接,关闭的连接会进入TIME_WAIT状态(默认等待60秒才释放),短时间内大量这类连接堆积,导致容器没有可用端口发起新的数据库连接。

以下是针对性的解决步骤:

1. 恢复并使用连接池,避免频繁创建连接

你之前移除连接池是错误操作,频繁新建/关闭连接正是问题根源:

  • 给后台轮询脚本使用长连接:初始化时建立一个数据库连接,轮询过程中复用这个连接,定期检查连接有效性(比如每次轮询前执行conn.ping()),失效时再重新建立。
  • 或者使用psycopg内置的连接池(psycopg_pool.ConnectionPool),配置固定数量的连接复用,避免每次轮询都新建连接。

示例代码(长连接方式):

import psycopg
from psycopg.rows import dict_row
import time

# 初始化时建立连接
conn = None
def get_db_connection(connection_info):
    global conn
    if conn is None or conn.closed:
        conn = psycopg.connect(conninfo=connection_info, autocommit=True, row_factory=dict_row)
    # 检查连接是否有效
    try:
        conn.execute("SELECT 1")
    except psycopg.OperationalError:
        conn = psycopg.connect(conninfo=connection_info, autocommit=True, row_factory=dict_row)
    return conn

# 轮询逻辑
def main():
    connection_info = "your_connection_string"
    while True:
        conn = get_db_connection(connection_info)
        # 执行查询逻辑
        with conn.cursor() as cur:
            cur.execute("SELECT * FROM pending_rows LIMIT 100")
            rows = cur.fetchall()
            # 处理数据
        # 适当休眠,避免高频轮询
        time.sleep(1)

2. 调整Docker容器的TCP参数,加速端口复用

通过修改内核参数,让系统更快复用TIME_WAIT状态的端口:

  • 启动容器时添加sysctl参数:
    docker run --sysctl net.ipv4.tcp_tw_reuse=1 --sysctl net.ipv4.tcp_fin_timeout=30 ...
    
    tcp_tw_reuse=1允许复用TIME_WAIT端口,tcp_fin_timeout=30把连接关闭后的等待时间从60秒改成30秒。
  • 或者在容器内修改/etc/sysctl.conf,添加以下内容后执行sysctl -p生效:
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_fin_timeout = 30
    

3. 替换轮询为PostgreSQL LISTEN/NOTIFY机制,彻底减少连接次数

轮询是低效的,改用PG的异步通知功能,只有当有新数据时才触发查询:

  1. 在Flask接口的插入逻辑后,添加通知:
    # 插入数据后执行
    with psycopg.connect(conninfo=connection_info) as conn:
        with conn.cursor() as cur:
            cur.execute("NOTIFY new_pending_rows;")
    
  2. 后台脚本建立长连接,监听通知,收到通知后再查询数据:
    def main():
        connection_info = "your_connection_string"
        with psycopg.connect(conninfo=connection_info, autocommit=True) as conn:
            with conn.cursor() as cur:
                cur.execute("LISTEN new_pending_rows;")
                print("Listening for new rows...")
                while True:
                    # 等待通知
                    conn.wait()
                    # 收到通知后查询处理数据
                    cur.execute("SELECT * FROM pending_rows LIMIT 100")
                    rows = cur.fetchall()
                    # 处理数据逻辑
    

这种方式不需要频繁轮询,全程复用一个长连接,彻底解决端口耗尽问题。

4. 修正PostgreSQL配置的不合理项

你之前调大max_connections到9000是没必要的,反而会占用大量内存导致PG性能下降:

  • 把max_connections调回合理值(比如500-1000),因为问题根本不是PG连接数不够。
  • 确认postgresql.conf中listen_addresses = '*'(允许所有IP连接),pg_hba.conf中添加容器所在网段的访问规则(比如host all all 172.17.0.0/16 md5,对应Docker默认网桥网段)。

5. 验证问题根源

在容器内执行ss -s查看TCP连接状态,重点看TIME-WAIT的数量,如果数值很大(比如上万),就确认是端口耗尽的问题。
在PG中执行SELECT count(*) FROM pg_stat_activity;,如果当前连接数远低于max_connections,说明PG连接数没有耗尽,进一步验证问题出在客户端端口。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 08:17:40