长连接不均源于连接状态未被正确感知或复用机制失效,需通过增强 access_log(添加 $connection_requests 和 $upstream_addr)、debug 级 error_log 及 stub_status 与后端 ss 统计交叉验证定位根因。

长连接不均不是配置没生效,而是连接状态没被正确感知或复用机制失效——日志里往往藏着真实原因。
重点看 access_log 里的连接特征
默认 access_log 只记录请求级信息,对长连接不敏感。需显式添加 $connection_requests 和 $upstream_addr 变量,才能看出单个 TCP 连接处理了多少请求、最终落到哪个后端:
- $connection_requests:当前 TCP 连接已处理的请求数(HTTP/1.1 下可高达数百)
- $upstream_addr:实际转发的目标地址(含端口),能确认 least_conn 是否真跳转到了连接数少的节点
- 示例日志格式:log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $connection_requests $upstream_addr';
上线后观察同一客户端 IP 的多条日志:若 $connection_requests 持续增长(如从 1→87→152),但 $upstream_addr 始终固定为某一台(如 192.168.1.10:8080),说明该连接未被重分配——least_conn 对已建立的连接不干预,只影响新连接建立。
error_log 中隐藏的连接池异常
当后端连接池耗尽时,Nginx 不会报错,而是静默降级为短连接,这正是长连接“看似在用、实则失效”的关键信号。需开启 debug 级 error_log 并关注以下关键词:
- "no live upstreams":所有 upstream server 的 max_conns 已满,且健康检查失败
- "upstream connection is busy":keepalive 连接池中无空闲连接,被迫新建连接
- "connect() failed (111: Connection refused) while connecting to upstream":后端拒绝连接,可能因连接数超限或进程僵死
特别注意:若日志中频繁出现 "upstream connection is busy",同时 access_log 中 $connection_requests 普遍低于 5,说明 keepalive 失效,每个请求都在新建连接——此时 least_conn 形同虚设。
结合 stub_status 验证连接分布真实性
仅看 Nginx 自身的 Active connections 不够,它包含所有连接(含客户端到 Nginx、Nginx 到后端)。必须交叉比对三处数据:
- Nginx stub_status 的 Active connections(总连接数)和 Reading/Writing/Waiting 分布
- 各后端机器上执行 ss -s | grep "tcp:" 或 netstat -an | grep :8080 | grep ESTAB | wc -l 得到的真实 ESTABLISHED 数
- 应用层监控(如 Prometheus + node_exporter)中各节点的 process_open_fds 和 net_conntrack_dialer_conn_established_total
若 Nginx 显示连接均匀,但后端 ss 统计严重倾斜(如 A 节点 12000,B 节点 2800),问题大概率出在:后端服务未正确复用连接(如 Java 应用未配置 HttpClient 连接池最大空闲数)、或客户端每请求都带 Connection: close 头强制断连。
排查路径要闭环:从日志反推配置有效性
不要孤立看某一条日志,而要构建“请求 → Nginx 决策 → 后端响应 → 连接状态”链路:
- 抓取一个客户端 IP 的连续 10 条 access_log,看 $upstream_addr 是否变化、$connection_requests 是否递增
- 对应时间窗口内 error_log 是否有连接池警告
- 该时段 stub_status 和后端 ss 统计是否匹配日志中的分发倾向
- 若发现 $upstream_addr 固定、$connection_requests 低、error_log 有 "upstream connection is busy",立即检查 upstream 块中 keepalive 值是否小于后端单机最大并发连接能力的 1/3











