Linux 服务器高并发连接优化思路

Linux 服务器高并发连接优化思路

Linux 服务器在高并发连接场景下的表现,很大程度上取决于内核 TCP/IP 协议栈的资源分配逻辑、文件描述符(fd)管理机制、连接状态机的生命周期控制,以及应用层对 accept 队列与 worker 线程池的合理使用。 真正能把单机并发连接从几千提升到几万甚至十万以上的优化,几乎都围绕以下几个核心约束展开:

  • fd 资源枯竭(进程/线程能打开的文件描述符上限)
  • 本地端口号耗尽(主动连接或被动连接的源端口/目标端口对有限)
  • TIME_WAIT 状态堆积(短连接场景最致命的瓶颈)
  • accept 队列与 SYN 队列溢出(listen backlog 与 tcp_max_syn_backlog)
  • 连接跟踪表(conntrack)与 NAT 表溢出(特别是 NAT 网关或 LVS 场景)
  • 单核软中断(ksoftirqd)瓶颈与网络中断分布不均
  • 内核调度开销与上下文切换压力

下面按优化收益从高到低实施优先级从前到后的顺序,系统梳理生产环境中真正有效的优化思路与核心逻辑。

一、最关键的第一步:fd 资源与进程限制(必须最先解决)

文件描述符是 Linux 高并发连接的“硬天花板”。

一个进程能同时持有的 fd 数量直接决定了它能 accept 和处理多少个并发 socket。 默认软限制通常只有 1024,硬限制 4096,这在任何高并发服务面前都远远不够。

优化逻辑

  • 系统全局打开文件数(fs.file-max)要提升到 100 万级别以上。
  • 每个服务进程的 nofile 限制要独立设置到 50 万~100 万(视内存规模)。
  • 优先使用 systemd 的 LimitNOFILE 而非 /etc/security/limits.conf(后者在容器化、非登录 shell 场景下经常失效)。
  • 同时把 nproc(进程数)也同步拉高,避免 fork 炸弹或线程爆炸把 fd 耗尽。

常见误区 很多人只改了 limits.conf,却忘了 systemd 服务没有继承该配置,导致实际生效的还是默认值。

二、TIME_WAIT 与端口资源管理(短连接场景的核心)

短连接(HTTP/1.0、频繁 API 调用、探活请求等)是 TIME_WAIT 堆积的最大元凶。 每个连接正常关闭后都会进入 TIME_WAIT 状态,默认持续 60 秒,这段时间内对应的本地端口(源端口)无法被复用。 当每秒新建连接数达到几千时,端口很快耗尽(可用端口范围默认只 32768–60999)。

优化逻辑

  • 把 tcp_fin_timeout 从默认 60s 降到 15s 或更低(加速 TIME_WAIT 回收)。
  • 开启 tcp_tw_reuse(允许 TIME_WAIT 状态的端口被新连接复用),这是短连接场景下提升并发能力最关键的一步。
  • 关闭 tcp_tw_recycle(NAT 环境下会导致严重连接失败,现代内核已默认关闭)。
  • 扩大本地可用端口范围(ip_local_port_range 从 32768 65535 改为 1024 65535)。
  • 增大 tcp_max_tw_buckets(TIME_WAIT 桶上限),防止内核直接丢弃新连接。

注意事项 tcp_tw_reuse 在服务端(被动连接)场景必须配合 tcp_timestamps=1 才能安全使用,否则可能导致旧连接的数据包被新连接误收。

三、accept 队列与 SYN 队列优化(被动连接的瓶颈)

listen() 系统调用的 backlog 参数决定了内核为该监听 socket 维护的半连接队列和已完成连接队列长度。 当队列满时,新来的 SYN 包会被直接丢弃(客户端看到 Connection refused 或超时)。

优化逻辑

  • 把 net.core.somaxconn 从默认 128 提升到 65535 或更高(全局最大 backlog)。
  • 把 net.ipv4.tcp_max_syn_backlog 从默认 256–1024 提升到 8192–32768(SYN 半连接队列)。
  • 应用层同步把 listen() 的 backlog 参数设置为 65535 或更大(Nginx 的 worker_connections、Java 的 ServerSocket backlog、Go 的 net.Listen 隐式 backlog)。
  • 监控 ss -ltn 中的 Send-Q 和 Recv-Q 是否持续堆积(队列压力表现)。

四、连接跟踪表与 NAT 优化(NAT 网关、LVS、容器网关场景)

当服务器作为 NAT 网关、LVS、HAProxy、Nginx 反代时,内核会为每个连接维护 conntrack 条目。 conntrack 表满后,新连接直接被丢弃。

优化逻辑

  • 增大 nf_conntrack_max(默认 65536 太小,建议 262144–1048576)。
  • 缩短 nf_conntrack_tcp_timeout_established(默认 432000s 太长,建议 300–1800s)。
  • 开启 nf_conntrack_tcp_loose=0(防止伪造连接绕过)。
  • 使用 nf_conntrack_buckets 适当增大 hash 表槽位,减少冲突。

五、多核中断均衡与网络栈卸载(高 PPS、高并发场景)

高并发连接必然带来高 PPS(每秒包数),容易导致单核 ksoftirqd 打满。

优化逻辑

  • 开启 RPS(Receive Packet Steering):将接收到的数据包分发到多个 CPU 核心处理。
  • 开启 RFS(Receive Flow Steering):让数据包尽量由处理该连接的进程所在 CPU 核心处理,减少跨核缓存失效。
  • 开启 XPS(Transmit Packet Steering):发送包也均匀分布。
  • 在支持 flow offload 的网卡上启用硬件加速(flowtable),将 established 连接的包直接交给网卡处理。
  • 调整 net.core.netdev_max_backlog(接收队列长度),避免包在网卡层被丢弃。

六、总结:高并发连接优化的分层优先级

  1. fd 限制拉到 100 万级(必须)
  2. TIME_WAIT 回收 + 端口复用(短连接场景必做)
  3. somaxconn + tcp_max_syn_backlog 拉满(被动连接队列)
  4. 连接跟踪表与超时参数调整(NAT/代理场景)
  5. 多核中断均衡(RPS/RFS/XPS/flow offload)
  6. 缓冲区与拥塞控制微调(高延迟场景)

一句话总结高并发连接优化的本质是“把所有能复用的资源都榨干,把所有会阻塞的队列都拉长,把所有会单核瓶颈的流量都打散”

Telegram
Telegram@IDCSELL