发布时间:2026年4月18日 预计阅读:6 分钟

Linux最大TCP连接数:不是65535,但也不是你想象的那样

Linux最大TCP连接数:是65535?

核心结论:单机能维护的TCP连接数从来就不取决于端口号。真正的瓶颈可能在文件描述符上限、临时端口耗尽、内存不足或内核参数限制——取决于你的业务场景是服务端还是客户端。

场景约束

业务背景:某高并发网关服务需要维护大量长连接到后端服务,在压测过程中连接数达到某个阈值后开始出现 connect: cannot assign requested address 错误。

系统版本:CentOS 7.9 / Linux 5.4 内核

限制条件

  • 服务运行在容器环境(Docker 20.10)中
  • 网关服务作为客户端,向多个后端服务发起连接
  • 连接类型为HTTP/1.1短连接,压测工具为wrk

影响面:所有到后端服务的请求全部失败,影响下游所有依赖方

现象与关键证据

压测命令与错误日志

# 使用wrk模拟客户端持续加压
wrk -t4 -c2000 -d60s --latency http://backend-cluster:8080/api

错误日志模式(来自nginx upstream配置):

2024/11/15 14:23:45 [error] 25671#25671: *1892344 connect() failed (99: Cannot assign requested address) 
while connecting to upstream, client: 10.0.1.100, server: 0.0.0.0:80

关键证据:错误码是 99(EADDRNOTAVAIL),不是 98(EADDRINUSE)。

两者含义完全不同:

  • EADDRINUSE (98):地址已被占用,你试图bind的端口已经被使用
  • EADDRNOTAVAIL (99):无法分配地址,没有可用端口可分配给这个连接

系统参数快照

# 文件描述符状态
$ cat /proc/sys/fs/file-nr
1344    0       8388608
# 格式:已分配数 / 已分配未使用数 / 系统最大值

# 用户ulimit
$ ulimit -n
1024

# 系统级file-max
$ cat /proc/sys/fs/file-max
8388608

# 临时端口范围(关键!)
$ sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 32768    60999
# 计算可用端口数:60999 - 32768 + 1 = 28232

# 当前TCP连接状态
$ ss -s
Total: 148 (kernel 1234)
TCP:   142 (estab 50, closed 87, orphaned 0, synrecv 0, timewait 87)
# 发现87个TIME_WAIT连接在堆积

排查路径

第一层:文件描述符是否耗尽

技术判断:如果 ulimit -n 只有1024,那单个进程最多只能打开1024个连接。但观察当前 file-nr 显示只用了1344,所以这里不是瓶颈。

# 验证单进程fd使用
$ ls /proc/$(pgrep -f nginx)/fd | wc -l
248

第二层:临时端口范围(这里是真正的瓶颈)

技术判断:服务端监听 0.0.0.0:80 时,每个连接占用一个文件描述符,不受端口数量限制。但网关作为客户端发起连接时,每个连接需要一个临时源端口。

# 查看连接到同一个后端IP:Port的连接数
$ ss -ant | awk '{print $4, $5}' | grep ':8080' | wc -l
28000+

# 查看可用临时端口
$ sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 32768    60999

当连接数超过28232时,系统无法分配新的临时端口,触发 EADDRNOTAVAIL。

方案取舍

方案一:扩展临时端口范围

# 临时生效
sysctl -w net.ipv4.ip_local_port_range="1024 65535"

# 永久生效
echo "net.ipv4.ip_local_port_range = 1024 65535" >> /etc/sysctl.conf

优点:立即生效,无需修改应用代码 缺点:会消耗更多端口资源,可能与其他服务冲突

方案二:启用TIME_WAIT端口重用

# 允许重用TIME_WAIT状态的端口
sysctl -w net.ipv4.tcp_tw_reuse=1

# 缩短FIN_WAIT_2超时
sysctl -w net.ipv4.tcp_fin_timeout=15

为什么不推荐 tw_recycle:它依赖时间戳选项,在NAT/LB环境下会导致部分客户端连接异常重建。这个参数在Linux 4.12后已被移除,但在旧系统上仍需注意。

方案三:调整文件描述符上限

# 调整用户级ulimit(临时)
ulimit -n 1000000

# 调整系统级nr_open(必须大于ulimit)
sysctl -w fs.nr_open=1100000

# 永久配置
cat >> /etc/security/limits.conf << 'EOF'
*    soft    nofile    1000000
*    hard    nofile    1000000
EOF

为什么不只调ulimit:如果不调 fs.nr_open,ulimit设置过大会报错。

$ ulimit -n 10000000
-bash: ulimit: open files: cannot modify limit: Operation not permitted

最终选择:组合方案

针对高并发网关服务(客户端角色),我推荐以下组合配置:

# /etc/sysctl.conf
fs.file-max = 2000000
fs.nr_open = 2000000
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 8192
net.netfilter.nf_conntrack_max = 1048576

取舍理由

  1. 扩展 ip_local_port_range 是解决客户端端口耗尽的直接手段
  2. tcp_tw_reuse 加速TIME_WAIT回收,增加可用端口周转率
  3. 提高 fs.nr_open 确保ulimit能设置到足够高
  4. 保留 nf_conntrack_max 以防iptables规则影响性能

实施方案与验证结论

实施步骤

# 1. 备份原配置
cp /etc/sysctl.conf /etc/sysctl.conf.bak

# 2. 应用新配置
sysctl -p

# 3. 验证生效
sysctl net.ipv4.ip_local_port_range
# 期望输出:net.ipv4.ip_local_port_range = 1024 65535

# 4. 修改limits.conf
cat >> /etc/security/limits.conf << 'EOF'
*    soft    nofile    1000000
*    hard    nofile    1000000
nginx soft    nofile    1000000
nginx hard    nofile    1000000
EOF

# 5. 重启服务使ulimit生效
systemctl restart nginx

# 6. 验证ulimit(需要重新登录或重启进程)
sudo -u nginx bash -c 'ulimit -n'

验证结论

方法一:逐步加压测试

# 逐步增加并发,观察错误率
for c in 10000 30000 50000; do
    echo "=== Testing with $c connections ==="
    wrk -t8 -c$c -d10s --latency http://backend-cluster:8080/api 2>&1 | \
        grep -E 'Latency|Requests|Socket errors|non-2xx'
done

修复前:连接数到28000左右开始出现大量 EADDRNOTAVAIL

修复后:连接数稳定在60000+ 无报错

方法二:监控指标对比

# 修复前
$ ss -s
Total: 28350 (kernel 1234)
TCP:   28342 (estab 120, closed 28215, orphaned 0, synrecv 0, timewait 28100)

# 修复后
$ ss -s
Total: 150 (kernel 1234)
TCP:   142 (estab 50, closed 87, orphaned 0, synrecv 0, timewait 87)
# TIME_WAIT从28100降到87,端口复用生效

方法三:确认瓶颈转移

# 确认不再是端口问题
$ sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 1024 65535
# 可用端口数:65535 - 1024 + 1 = 64512

# 确认ulimit已生效
$ sudo -u nginx bash -c 'ulimit -n'
1000000

边界条件

什么时候端口数真的是瓶颈

当且仅当以下条件同时满足时:

  1. 你是客户端角色——发起连接的一方
  2. 所有连接指向同一个目标 IP:Port
  3. 短连接且TIME_WAIT堆积
  4. ip_local_port_range 没有扩展

什么时候ulimit才是瓶颈

每个TCP连接需要占用一个文件描述符。默认的1024对于生产服务远远不够。

容器环境额外约束

在Docker环境中,文件描述符限制可能受多个层面限制:

# 检查容器内限制
docker exec 
<container_id> cat /proc/sys/fs/file-nr

# 检查宿主机限制
cat /proc/sys/fs/file-max

# 检查Docker daemon配置
cat /etc/docker/daemon.json
{
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 8400000,
      "Soft": 8400000
    }
  }
}

关键判断:如果容器内 ulimit -n 是1024,但宿主机 fs.file-max 是8388608,那瓶颈在容器的ulimit限制,需要用 --ulimit nofile=1000000:1000000 启动参数覆盖。

内存约束

每个TCP连接大约占用3KB-10KB内存(取决于协议栈buffer大小)。100万连接意味着至少需要3GB-10GB内存专门用于连接维护。

# 估算单个连接内存占用
$ cat /proc/sys/net/ipv4/tcp_rmem
4096    16384   4194304
# 最小/默认/最大 receive buffer

$ cat /proc/sys/net/ipv4/tcp_wmem
4096    16384   4194304
# 最小/默认/最大 send buffer

# 10000连接 × 32KB(buffer) ≈ 320MB

长连接 vs 短连接场景对比

场景 主要瓶颈 优化方向
HTTP短连接 临时端口、TIME_WAIT 连接复用、端口扩展、tw_reuse
WebSocket长连接 文件描述符、内存 ulimit调高、内存规划
gRPC长连接 文件描述符、内存 同上
数据库连接池 文件描述符、连接池上限 调整服务连接数限制

总结

瓶颈类型 典型症状 检查命令 解决方案
ulimit过小 too many open files ulimit -n 调整 /etc/security/limits.conf
端口耗尽 cannot assign requested address ss -s 看TIME_WAIT 扩展 ip_local_port_range + tcp_tw_reuse
内核fd上限 ulimit无法超过某个值 cat /proc/sys/fs/nr_open sysctl -w fs.nr_open=xxx
内存不足 OOM killed free -h 增加内存或减少连接数

回到最初的问题:Linux最大TCP连接数是多少?

答案是:取决于你遇到的具体瓶颈是什么。

对于服务端,瓶颈通常是文件描述符;对于客户端,瓶颈通常是临时端口。不要用65535来回答这个问题,也不要用65535来指导系统调优。先定位瓶颈,再针对性优化。

我不推荐的做法:上来就改 ip_local_port_range,却不检查ulimit和内核参数。TCP连接数问题从来不是单一因素导致的。

继续浏览

这篇文章读完后,你可以从首页、当前专题或左侧列表继续深入阅读

左侧已经放入当前专题的文章列表,你可以直接跳到同专题的其他帖子,不需要回退浏览器重新找内容。

当前文章:Linux最大TCP连接数:不是65535,但也不是你想象的那样 所属入口:Linux相关 预计阅读:6 分钟
回到首页 查看同类文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

8 + 2 =