单机并发下的 TCP 参数实测记录
小机器上跑网关,连接数一多就开始出现零星超时。网上关于内核参数的文章很多,但多数没说清楚是在什么负载下测的。这里记录一次在 2 核 1.6G 机器上的对比,数据不漂亮,但足够判断哪些参数值得改。
先看瓶颈在哪
# 监听队列溢出:这两行有增长,说明 backlog 不够
nstat -az | grep -E 'ListenOverflows|ListenDrops'
# 连接跟踪表
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
# 文件描述符
cat /proc/sys/fs/file-nr
如果 ListenOverflows 一直是 0,那 backlog 再大也没意义,问题在别处。这是最容易浪费时间的地方:先加参数,再看指标,发现没变化,然后怀疑人生。
值得改的几项
| 参数 | 默认 | 调整后 | 说明 |
|---|---|---|---|
| net.core.somaxconn | 4096 | 16384 | 应用 listen() 的上限 |
| net.ipv4.tcp_max_syn_backlog | 1024 | 8192 | SYN 队列,抗突发 |
| net.ipv4.ip_local_port_range | 32768 60999 | 10240 65000 | 出站连接可用端口 |
| fs.file-max | 9223372036854775807 | 不改 | 现代内核基本够用 |
| net.ipv4.tcp_tw_reuse | 2 | 2 | 只影响出站,默认已是 2 |
注意第一行和第三行:somaxconn 只是上限,应用自己的 backlog 参数(比如 Nginx 的 listen ... backlog=)不超过它就行,两边都要看。
拥塞控制:BBR 的收益取决于丢包
同一条线路,从 2% 丢包开始,BBR 相比 cubic 的差距就非常明显;在干净的链路上两者几乎一样。切换方式:
modprobe tcp_bbr
cat >> /etc/sysctl.d/99-bbr.conf <<'EOF'
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
EOF
sysctl --system
sysctl net.ipv4.tcp_congestion_control
坑:开了 BBR 之后
tc qdisc 必须是 fq 或 fq_codel。有的镜像默认 pfifo_fast,BBR 仍能工作但效果打折。实测结果
环境:2 vCPU / 1.6G,客户端 200 并发长连接,单条 4KB 请求,持续 5 分钟。只改内核参数,不动应用。
| 配置 | 吞吐 | p99 延迟 | ListenOverflows |
|---|---|---|---|
| 默认 | 182 MB/s | 41 ms | 1327 |
| somaxconn=16384 | 205 MB/s | 23 ms | 0 |
| 再加 tcp_max_syn_backlog | 207 MB/s | 22 ms | 0 |
| 再加 BBR(线路 1.8% 丢包) | 246 MB/s | 19 ms | 0 |
结论只对这台机器和这条线路成立:真正起作用的是 backlog,BBR 的收益来自丢包环境。换到干净的机房链路,最后一行的提升会缩到个位数。
写进配置
/etc/sysctl.d/99-net.conf
net.core.somaxconn = 16384
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.ip_local_port_range = 10240 65000
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_mtu_probing = 1
tcp_mtu_probing=1 是给那些 PMTU 黑洞的环境准备的,代价是少量额外的探测包。走隧道的时候建议开。