单机千万级长连接需绕过内核协议栈:XDP、DPDK或智能网卡是唯一可行路径,sysctl调优仅治标;必须禁用conntrack等开销模块,并由应用层自主管理连接生命周期。

千万级长连接不是调几个 sysctl 就能搞定的
直接说结论:单机支撑 C10M(千万连接)长连接,sysctl 参数调优只是最表层动作,真正瓶颈在协议栈路径本身。内核默认 TCP 栈在百万连接时已显疲态,到千万级时,中断处理、conntrack 查表、socket 内存管理、软中断调度全都会成为硬伤。你看到的“连接建立失败”“CPU 软中断 100%”“dmesg 里满屏 orphaned sockets”,都不是配置错了,而是架构到了临界点。
必须绕过内核协议栈:XDP 或 DPDK 是现实选择
当连接数跨过 500 万,net.ipv4.tcp_tw_reuse、net.core.somaxconn 这类参数就失去意义——它们优化的是“连接建立和回收效率”,而千万级长连接的核心矛盾是“每个连接不发包也吃内存 + 每个包都要过完整 TCP/IP 栈”。此时唯一可行路径是绕过内核:
-
XDP:在网卡驱动层做包过滤/转发,延迟低、吞吐高,适合做四层负载均衡或连接代理,但不能处理完整 TCP 状态机 -
DPDK:用户态轮询收发包,彻底 bypass 内核网络栈,配合自研连接管理器可支撑千万级 idle 连接,但开发成本高、调试难、无法直接复用epoll/sendfile等系统调用 - 智能网卡(如 NVIDIA BlueField):把连接跟踪、TCP 终结甚至 TLS 卸载到硬件,适合云厂商或定制化部署,普通业务线难以落地
别信“加内存 + 调 tcp_mem 就能上千万”的说法——一个 idle socket 在 5.10+ 内核下仍占约 4–6 KB 内核内存,千万连接光 socket 结构体就要 40–60 GB,还不算 conntrack 表、sk_buff、页缓存等开销。内存不是瓶颈,是幻觉的起点。
哪怕用内核栈,也得关掉所有“温柔但昂贵”的功能
如果暂时无法切 XDP/DPDK,又必须压测或过渡性支撑 500 万以上长连接,请先停掉所有会引入全局锁或线性扫描的功能:
- 关掉
net.netfilter.nf_conntrack_enable(即禁用 conntrack),否则每个包都要查哈希表,连接数一过百万,nf_conntrack查表就成 CPU 热点 -
net.ipv4.tcp_tw_recycle = 0(必须为 0,NAT 下必断连;且现代内核已移除该参数,设了也无效) - 禁用
tcp_slow_start_after_idle,避免长连接空闲后重传窗口归零 - 关闭
net.ipv4.ip_forward和所有 netfilter 模块(iptables/nftables规则清空),减少包路径上的 hook 调用 -
net.core.bpf_jit_enable = 0,除非你真用 BPF 做连接管理,否则 JIT 编译器会抢 CPU
这些不是“建议”,是实测中发现的千万级连接下导致软中断卡死的常见开关。开一个,可能就少撑 50 万连接。
应用层必须放弃依赖内核的连接生命周期管理
内核的 CLOSE_WAIT、TIME_WAIT、连接超时检测,在千万连接规模下全是伪命题。你无法靠 tcp_fin_timeout 或 keepalive 参数来“自动清理”——因为内核根本扫不过来。真实做法是:
- 服务端自己实现心跳 + 连接空闲超时(比如 5 分钟无读写即 close),不依赖
tcp_keepalive_* - 客户端必须主动发 FIN,服务端不做半关闭等待;所有连接走 graceful shutdown 流程
- 用
SO_ATTACH_REUSEPORT_CBPF或自定义 eBPF 程序做连接分发,替代传统SO_REUSEPORT的哈希冲突问题 - 监控重点不是
ss -s输出,而是/proc/net/sockstat中sockets: used和tcp:行的orphan数量——一旦orphan持续 > 10 万,说明内核已开始丢连接
最后提醒一句:C10M 不是性能目标,是架构分水岭。你调的不是 Linux 参数,是在决定要不要把网络栈从内核里“拔出来”。没想清楚这点,所有 sysctl -w 都只是给即将崩溃的系统多续几秒呼吸。


















