工程
Linux TCP 服务端调优
删掉过时魔改参数,只保留 2026 年仍然适用的 Linux TCP 服务端调优基线。
很多旧的 TCP 调优文章都带着明显的时代痕迹:
- 把代理场景、路由转发场景、普通服务端场景混在一起
- 往
/etc/sysctl.conf里塞一大堆已经废弃、默认已经合理、或者根本不该全局修改的参数 - 只给“魔改参数”,不给验证方法
Linux 5.x / 6.x 下,更靠谱的思路是:
- 先确认瓶颈是在应用、内核、NIC,还是链路本身
- 只改少量确实相关的参数
- 每次改动都能用指标或压测结果验证
先看什么
先别急着改 sysctl,先看这些:
# 当前拥塞控制算法和可选项
sysctl net.ipv4.tcp_congestion_control
sysctl net.ipv4.tcp_available_congestion_control
# 当前 qdisc
sysctl net.core.default_qdisc
tc qdisc show dev eth0
# TCP 概览
ss -s
ss -lnt
# 协议计数器
nstat -az
# 网卡统计
ethtool -S eth0
如果问题其实是:
- 进程
ulimit -n太小 - 应用监听 backlog 太小
- 单进程 accept 太慢
- 用户态线程池、数据库连接池、磁盘 IO 才是瓶颈
那改 TCP 参数通常不会有本质帮助。
一组足够保守的基线
下面这份配置,适合大多数普通 Linux TCP 服务端作为起点:
# /etc/sysctl.d/90-tcp-server.conf
# listen backlog 上限。Linux 5.4 之后默认已经是 4096,
# 显式写出来是为了避免不同发行版行为不一致。
net.core.somaxconn = 4096
# 半连接队列上限。只有在连接高峰时才会明显影响结果。
net.ipv4.tcp_max_syn_backlog = 4096
# 保留 syncookies 作为 SYN backlog 溢出时的兜底手段。
net.ipv4.tcp_syncookies = 1
# 如果内核支持 BBR,配合 fq 通常是公网链路下一个稳妥的起点。
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# 对 PMTU blackhole 相对友好。
net.ipv4.tcp_mtu_probing = 1
应用后执行:
sudo sysctl --system
然后立刻确认:
sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog
sysctl net.ipv4.tcp_congestion_control
sysctl net.core.default_qdisc
这些参数为什么值得保留
net.core.somaxconn
这是 listen() backlog 的全局上限。内核文档说明它对应用户态常见的 SOMAXCONN,默认值在 Linux 5.4 之后已经是 4096,不再是很多老文章里写的 128。
要注意两点:
- 应用代码或框架自己传给
listen()的 backlog 不能太小 - 只调高
somaxconn,不改应用 backlog,没有意义
net.ipv4.tcp_max_syn_backlog
这是每个监听 socket 的半连接队列上限。内核文档明确写了:服务端如果因为过载而丢积压连接,可以考虑增加它,同时也要一起检查 somaxconn。
net.ipv4.tcp_syncookies
这不是吞吐优化开关,而是 backlog 溢出时的回退机制。内核文档甚至专门提醒:它不能拿来支撑“合法高负载”,如果你因为正常流量触发大量 syncookies,优先应该排查 backlog、accept 速度、应用处理能力,而不是把它当性能参数。
net.core.default_qdisc + net.ipv4.tcp_congestion_control
如果内核支持 bbr,它依然是公网高 RTT / 带宽波动场景里一个值得先试的选择。
更精确地说:
- Google 的 BBR 文档说明,BBR 已经在 Linux 4.9 及以后可用
- 对于 Linux 4.20 及以后,已经不再“严格要求”安装
fq才能使用 BBR - 但
fq对高负载服务器通常仍然更合适
所以今天更稳妥的说法不是“必须启用 fq 才能开 BBR”,而是:
- 新内核上,BBR 不再硬依赖
fq - 但如果你控制的是本机发出的 TCP 流量,
fq仍然是很好的默认选择
如果你的内核没有 bbr,那就先保留默认的 cubic,不要为了“调优”去打第三方魔改补丁。
net.ipv4.tcp_mtu_probing
这个参数控制 TCP 的 PLPMTUD 行为。设为 1 时,默认关闭,只在检测到 ICMP blackhole 问题时启用探测;这是比“强行关闭 PMTU 发现”更保守的选择。
这些参数不要再无脑抄了
net.ipv4.tcp_tw_recycle
这个参数在现代 Linux 内核里已经没了。还看到有人让你打开它,可以直接判定那篇文章太老。
net.ipv4.tcp_tw_reuse
现代内核文档里它仍然存在,但默认值已经是 2,也就是仅对 loopback 流量启用。官方文档还明确写了:不要在没有明确专家建议的情况下修改它。
结论很简单:
- 不要再把它当成“高并发优化必开项”
- 更不要全局乱调 TIME_WAIT 相关参数来碰运气
net.ipv4.tcp_fin_timeout
这个参数只影响 orphaned FIN_WAIT_2 连接,不是通用“连接超时”旋钮。很多旧文把它解释成“加快连接回收”,这并不准确。
net.ipv4.tcp_fack
内核文档已经写得很直接:这是 legacy 选项,已经没有效果。可以删掉。
net.ipv4.tcp_rmem / net.ipv4.tcp_wmem / net.ipv4.tcp_mem
这些不是不能动,而是大多数机器没必要上来就手工写成几万倍大值。
内核文档说明:
- TCP 默认就会做接收缓冲自动调优
tcp_mem的默认值会在启动时根据可用内存自动计算
所以如果你没有明确的高 BDP 场景、没有抓到 buffer 不足的证据、也没有配套的压测结果,就先别碰它们。
net.core.netdev_max_backlog / net.core.netdev_budget / net.core.netdev_budget_usecs
这些参数是更偏 NIC / NAPI / PPS 的调度控制,不是普通 Web 服务“高并发优化套餐”。
内核文档对它们的定义分别是:
netdev_budget: 一次 NAPI polling cycle 里最多处理多少包netdev_budget_usecs: 一次 polling cycle 最多跑多久netdev_max_backlog: 输入侧来包速度高于内核处理速度时,可排队的最大包数
只有当你已经通过 softnet_stat、ethtool -S、丢包计数器确认瓶颈在这里时,再动这些参数。
全局 keepalive
tcp_keepalive_time、tcp_keepalive_intvl、tcp_keepalive_probes 并不是典型的吞吐优化参数。
它们更像“连接活性策略”:
- 长连接 RPC、隧道、MQTT、数据库连接池可能需要
- 普通短连接 HTTP 服务通常不是靠改这三个参数解决问题
如果你只想让某类连接更快失败,优先考虑应用层心跳或 socket 级别的 TCP_USER_TIMEOUT / keepalive 设置,而不是把整台机器的默认 keepalive 策略一起改掉。
net.ipv4.ip_local_port_range
这个参数只在你有大量 主动发起 的出站连接时才常见,比如:
- 反向代理
- 抓取器
- 大量短连接的 API client
- NAT 网关
它不是典型“服务端吞吐优化”参数。默认范围不够时再调,而且要避开保留端口。
tcp_fastopen 要不要开
可以,但不要当成默认基线。
内核文档里 tcp_fastopen 已经是 bitmap 配置:
0x1: 客户端支持,默认已开0x2: 开启服务端支持0x400: 让所有 listener 默认支持 Fast Open
更现实的做法是:
- 先确认客户端和服务端应用真的支持 TFO
- 先按单服务逐步开,不要整机全 listener 一刀切
如果你只是普通内网服务,先把 backlog、accept、进程数、FD 限额理顺,收益通常更大。
调优时最容易忽略的两件事
1. 文件描述符上限
ulimit -n
cat /proc/$(pidof your-service)/limits | grep files
如果服务本身连足够的 socket 都开不出来,TCP 参数再漂亮也没用。
2. 应用 backlog 和 accept 模型
应用层至少要确认:
- backlog 没被框架写死成很小的值
- 多进程 / 多线程 accept 没有成为瓶颈
SO_REUSEPORT、worker 数、event loop 没明显失衡
很多“TCP 调优见效不大”的根因,其实是用户态没接住连接。
如何验证是否真的变好
不要只看“网页打开更快了”。至少做两类验证。
压测
今天优先用 iperf3,不是老 iperf:
# 服务端
iperf3 -s
# 客户端,正向 30 秒
iperf3 -c your-host -t 30
# 客户端,反向测试服务端发送能力
iperf3 -c your-host -R -t 30
# 多流测试
iperf3 -c your-host -P 4 -t 30
观测
在调优前后对比这些指标:
ss -s
nstat -az
ethtool -S eth0
sar -n TCP,ETCP 1
如果你改完之后:
- 重传没降
- backlog 溢出没降
- softirq / NIC drop 没改善
- 应用 P99 延迟没改善
那这次调优基本就不算成立。
结论
如果只想要一个 2026 年还能放心保留的结论版:
- 先排查应用 backlog、FD 限额、accept 能力
- 保守基线只保留
somaxconn、tcp_max_syn_backlog、tcp_syncookies、tcp_mtu_probing - 如果内核支持,优先试
bbr + fq - 不要再抄
tcp_tw_recycle、tcp_fack、超大tcp_mem netdev_*、keepalive、端口范围都属于“有证据再改”的第二层参数
参考
- Linux kernel docs: IP Sysctl
- Linux kernel docs: Documentation for /proc/sys/net
- iproute2 man page: tc-fq(8)
- Linux man page: ip(7)
- ESnet: iperf3 documentation
- Google BBR: bbr-quick-start.md