线上出现“网站打不开”,监控却显示后端 CPU 不高、数据库也没有慢查询。连接数耗尽经常被误判成服务器资源不足,实际问题可能藏在 TCP 连接、反向代理工作进程、请求排队机制,甚至上游超时设置中。
如果你正在选机器,或者想先把线路和配置跑通再谈长期方案,可以先看看这几家的线路说明和技术参数:neburst(全球云服务器),先看清带宽线路、流量策略和退款条款,再决定要不要迁。
更棘手的是,客户端超时并不代表请求没有到达后端。代理可能已经建立 TCP 连接,却因为工作进程饱和、连接数上限或上游响应过慢,把请求长时间卡在队列里。此时盲目增加机器或重启服务,只能短暂恢复,无法解释故障究竟发生在哪一层。
先分清:TCP 真的“用完”了吗?
排查第一步不是直接调大参数,而是同时观察 TCP 状态、文件描述符和代理进程。连接数上限首先受进程级限制约束,例如服务进程的 ulimit -n、反向代理的 worker_connections,以及容器或 systemd 的描述符限制。任何一个环节偏小,都可能让新连接在应用层之前就失败。

可复现的方法是逐步提高并发:先用 20、50、80 个请求建立持续连接,再用 100、150、200 个请求观察失败点。每次压测都记录 ss -s 的 TCP 状态、代理错误日志、进程 fd 数量和后端 active connections。若失败数量接近某个明确阈值,优先怀疑连接数上限;若 ESTABLISHED 很多但应用连接很少,则要检查代理是否只完成了握手,没有把请求交给工作进程。
还要区分 TIME_WAIT 堆积和真正的 established 连接耗尽。前者常见于短连接、高并发或连接复用异常,可能需要检查连接池、超时回收和复用策略;后者才更接近并发容量问题。不要只看系统总连接数,因为监听端口、代理到后端的连接和客户端连接并不属于同一个池。
再判断:请求卡在代理,还是卡在上游?
如果文件描述符和 TCP 状态都正常,故障点可能转向工作进程饱和。反向代理通常由 master 创建若干 worker,每个 worker 同时处理多个连接;worker 数量、内存、单进程最大连接数共同决定有效吞吐。连接建立不等于请求被处理,反向代理转发还可能受到后端地址数量、连接池、上游响应时间影响。

判断时可以做两组对照。第一组把并发固定为 80,逐步缩短上游响应时间,观察排队是否消失;第二组保持响应不变,将上游超时从 30 秒调整为 5 秒,观察客户端是否更快收到明确的 504,而不是一直等待。这样可以验证上游超时联动是否掩盖了后端变慢。若缩短超时后错误从“连接失败”变成“网关超时”,连接本身大概率已经建立,问题在请求处理或上游响应。
实际调优应按“文件描述符限制→TCP 复用与短连接→代理工作进程→后端连接池→请求排队机制→上游超时联动”的顺序进行,每一步只改一个参数,再用相同并发和请求间隔复测。切忌同时放大 worker、超时和连接池,否则日志只显示大量 502 或 504,无法确认是哪一层先达到瓶颈。ServLlama 这类工具可辅助查看连接和进程状态,但最终仍要回到指标、错误码和压测结果的对应关系。
反向代理转发与工作进程饱和
当请求经过 Nginx、Apache 或云厂商负载均衡时,连接通常会经历“客户端代理上游服务”两段传输。代理会为每个请求维护前端连接和后端连接,连接池大小、工作进程数以及上游服务可接受的并发量,决定了真正的承载上限。只提高监听端口的 backlog 并不能解决问题,因为瓶颈可能出现在代理读取请求、向后端建立连接,或等待上游响应的阶段。
如果工作进程数量偏少,单个进程又承担了大量 TLS 解密、压缩和日志写入,CPU 很快就会打满。此时新的请求会进入请求排队机制,表现为客户端等待时间长、服务端连接数却不一定持续升高。排查时要区分连接数、活跃请求数和队列长度,不能仅凭 netstat 或 ss 的连接总数判断原因。
常见误区是把 proxy_read_timeout、proxy_connect_timeout 和 proxy_send_timeout 设置成相同的巨大数值。这样虽然表面上“不会超时”,却会让失效连接长期占用资源,队列越长,上游超时联动越严重。上游应用变慢时,代理仍会不断创建新连接,最终形成连接堆积和重试放大。应先设置合理的连接超时,再根据接口耗时调整读取超时,并限制同一上游的最大并发数。

另一个容易踩的坑是忽略 Keep-Alive 和连接复用。代理到上游的长连接数量,通常不应与客户端连接数一一对应;如果发现两者完全相等,可能是连接复用没有生效,或者上游应用频繁关闭连接。还要检查连接池是否按域名、端口或路径划分,避免高流量接口占满共享池项。
可执行的检查清单
第一步,分别查看客户端连接、代理前端连接、代理到上游的连接,以及应用侧的 accepted、active、idle、waiting 指标,确认连接究竟耗尽在哪一层。第二步,检查连接数上限:系统文件描述符限制、代理 keepalive 池、容器连接限制、数据库连接池和上游线程池都不能被遗漏。
第三步,观察 CPU、内存、事件循环延迟和请求队列,确认是否属于工作进程饱和。若 CPU 不高但 waiting 持续增加,应优先检查上游响应、锁等待和网络丢包,而不是盲目增加进程。
第四步,核对代理与应用的超时是否形成合理链路,例如上游处理时间应小于代理读取超时,并给失败重试设置次数上限。第五步,在低峰期逐步压测,观察连接复用率、队列长度、错误率和上游资源变化,找到真正的拐点。
最后保留调整前后的监控曲线,并设置连接数、队列长度和超时比例告警。连接数耗尽往往不是单一参数错误,而是代理、应用、数据库和系统限制共同作用的结果;沿着请求链路逐层定位,才能避免按下葫芦浮起瓢。


喜欢
顶
难过
囧
围观
无聊





