这种情况在运维排查中非常经典,通常被称为“假死”或“资源错配”。当 CPU 和内存都还有大量空闲,但连接数(Connections)却打满导致新请求无法建立时,问题往往不在计算能力上,而是在系统资源限制、网络栈配置或中间件瓶颈这几个维度。
以下是按可能性从高到低的排查思路和具体原因分析:
1. 文件描述符(File Descriptors, FD)耗尽
这是最常见的原因。在 Linux 系统中,每一个网络连接(Socket)本质上都是一个打开的文件。如果进程能打开的最大文件数有限制,一旦达到上限,即使 CPU 再闲,也无法创建新的 Socket 连接。
- 现象:日志中可能出现
Too many open files错误。 - 排查方法:
- 查看当前用户或进程的限制:
ulimit -n - 查看当前已打开的文件句柄数:
lsof -p <pid> | wc -l或cat /proc/<pid>/limits - 检查全局限制:
/etc/security/limits.conf中的nofile设置。
- 查看当前用户或进程的限制:
- 解决:修改
/etc/security/limits.conf调大soft nofile和hard nofile,并重启服务生效。对于高并发场景,建议设置为 65535 或更高。
2. 本地端口范围(Local Port Range)不足
如果你的应用是作为客户端去连接上游服务(如调用数据库、Redis、其他微服务),或者在某些反向XX模式下,每次新建连接都需要占用一个本地 ephemeral port(临时端口)。
- 原理:Linux 默认可用的临时端口范围通常是
32768-60999,约 2.8 万个端口。如果并发连接数超过这个范围,且 TIME_WAIT 状态积累过多,就会报Cannot assign requested address错误。 - 排查方法:
- 查看当前可用端口范围:
cat /proc/sys/net/ipv4/ip_local_port_range - 查看处于 TIME_WAIT 状态的连接数:
netstat -an | grep TIME_WAIT | wc -l
- 查看当前可用端口范围:
- 解决:扩大端口范围,例如将
ip_local_port_range调整为1024 65535。同时优化 TCP 参数,提速 TIME_WAIT 回收(见下文第 4 点)。
3. 内核网络参数限制(TCP Stack Limits)
Linux 内核本身对并发连接有一些硬性或软性限制,尤其是在处理大量短连接或高频握手时。
- 关键参数:
somaxconn:监听队列的最大长度。如果 Web 服务器(Nginx/Tomcat)配置的 backlog 大于此值,多余连接会被丢弃。- 检查:
sysctl net.core.somaxconn - 解决:
sysctl -w net.core.somaxconn=65535
- 检查:
tcp_max_syn_backlog:半连接队列(SYN Queue)的大小。在高并发 SYN 攻击或正常高并发下,如果此值过小,会导致 SYN 丢包,连接失败。tcp_fin_timeout:FIN-WAIT-2 状态的超时时间。如果设置过长,会占用更多资源。
- 解决:在
/etc/sysctl.conf中调整这些参数并执行sysctl -p生效。
4. TIME_WAIT 堆积
虽然 CPU 空闲,但如果存在大量处于 TIME_WAIT 状态的连接,它们会占用本地端口和内存,并且不会立即释放。这在 HTTP 短连接场景(如传统 REST API)中尤为明显。
- 排查方法:
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'观察
TIME_WAIT的数量是否异常高。 - 优化策略:
- 开启 TCP Keepalive:减少无效长连接的资源占用。
- 启用 TCP Fast Open (TFO):减少三次握手开销(需内核支持)。
- 调整 tcp_tw_reuse:允许将处于 TIME_WAIT 的 socket 用于新的 outgoing 连接(注意安全性,仅限可信内网环境)。
sysctl -w net.ipv4.tcp_tw_reuse=1
- 改用长连接:如果是内部服务调用,务必使用 HTTP/2、gRPC 或数据库连接池,避免频繁建连断连。
5. 云厂商安全组/网络 ACL 限制
国内主流云厂商(阿里云、腾讯云、华为云等)的安全组和网络 ACL 并非无限放行。虽然它们通常不直接限制“连接数”,但某些底层网络设备或负载均衡器(SLB/CLB)可能有自己的会话表限制。
- 注意:如果你使用的是云服务器 ECS 直连公网,一般不涉及此问题。但如果通过 SLB 转发,需检查 SLB 实例的规格限制(如每秒新建连接数 CPS、并发连接数 CCS)。ECS 侧连接数满,可能是 SLB 侧先达到了其规格上限,导致后续连接被丢弃或延迟极高,表现为 ECS 接收不到新连接。
- 排查:检查云监控中的 SLB 指标,对比 ECS 的网络流入流量和 SLB 的流出流量是否匹配。
6. 应用层线程池/连接池耗尽
有时候“连接数达到上限”指的是应用内部的连接池(如 JDBC 连接池、HTTP Client 连接池)满了,而不是操作系统层面的 TCP 连接满了。
- 现象:应用日志中出现
Connection pool exhausted或Timeout waiting for idle connection。 - 原因:业务逻辑中存在慢查询、死锁或未及时关闭的连接,导致连接池中的连接被长时间占用,新请求无法获取连接。
- 排查:检查应用监控(如 Arthas、JMX、APM 工具),查看线程堆栈,确认是否有线程阻塞在等待数据库或外部 API 响应。
快速排查命令汇总
# 1. 检查文件描述符限制
ulimit -n
# 2. 检查当前打开的文件句柄数(替换 <pid> 为实际进程ID)
lsof -p <pid> | wc -l
# 3. 检查网络连接状态分布
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
# 4. 检查内核网络参数
sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog
cat /proc/sys/net/ipv4/ip_local_port_range
# 5. 查看实时连接趋势(需要 ss 命令)
ss -s
总结建议
- 优先检查
ulimit -n和lsof,这是最容易被忽视且最常见的瓶颈。 - 其次检查
TIME_WAIT数量,如果是短连接架构,考虑扩大端口范围或启用tcp_tw_reuse。 - 调整
somaxconn和tcp_max_syn_backlog,确保内核队列足够深。 - 最后审视应用架构,是否应该从短连接改为长连接,是否使用了合理的连接池管理。
记住:CPU 空闲不代表系统健康,它只是说明你没有在进行繁重的计算,但可能正在被 I/O、网络或系统资源限制所卡住。
云技术博客