4. 网络环境调优:TCP/IP参数调优、网卡多队列与巨型帧
吞吐测试里,网络环境经常是那个“看不见的瓶颈”。
你机器性能再强,网卡参数没调对,数据一样上不去。我见过太多团队,花大价钱买硬件,结果被几个内核参数卡死。说白了,网络调优就是让数据包走得快、走得稳。
这一章,咱们把TCP/IP参数、网卡多队列、巨型帧这三个核心点讲透。
4.1 TCP/IP参数调优:别让内核拖后腿
Linux内核默认的TCP参数,是为通用场景设计的。吞吐测试这种高并发、大流量的场景,必须手动调。我习惯先改这几个关键参数:
| 参数名 | 默认值 | 推荐值 | 作用 |
|---|---|---|---|
tcp_tw_reuse |
0 | 1 | 允许将TIME_WAIT状态的socket用于新连接 |
tcp_fin_timeout |
60 | 15-30 | 减少FIN_WAIT2状态的等待时间 |
tcp_tw_recycle |
0 | 0(已废弃,不建议开启) | 快速回收TIME_WAIT(NAT环境下有坑) |
net.ipv4.ip_local_port_range |
32768 60999 | 1024 65535 | 扩大可用端口范围 |
tcp_max_syn_backlog |
128 | 65536 | 增大半连接队列长度 |
4.1.1 tcp_tw_reuse:复用TIME_WAIT连接
高并发场景下,客户端主动关闭连接后,会进入TIME_WAIT状态。默认要等2MSL(约60秒)才能释放。你想想看,每秒几万个请求,端口很快就耗尽了。
tcp_tw_reuse 允许内核在安全前提下,把TIME_WAIT状态的socket分配给新连接。我在压测短连接服务时,这个参数几乎是必开的。
核心逻辑: 开启后,内核会检查TIME_WAIT socket的时间戳,如果新连接的初始序列号比旧连接大,就直接复用。不会影响数据完整性。
4.1.2 tcp_fin_timeout:缩短FIN_WAIT2等待
这个参数控制的是被动关闭方进入FIN_WAIT2后的超时时间。默认60秒,太长了。我一般调到15秒,极端场景下调到5秒也行。
但要注意,调得太低可能导致正常慢速连接被误杀。嗯,这里要结合业务场景权衡。
避坑指南: 我曾经在NAT环境下误开了 tcp_tw_recycle,结果导致部分客户端连接失败。因为NAT后面多个客户端共享同一个公网IP,时间戳混乱。记住:tcp_tw_recycle 在Linux 4.12之后已被移除,别再用它。
4.1.3 其他关键参数
- net.core.somaxconn:listen队列长度,默认128,建议调大到65535。
- net.ipv4.tcp_keepalive_time:TCP保活探测间隔,默认7200秒,压测时可调小到300秒。
- net.core.rmem_max / wmem_max:socket接收/发送缓冲区最大值,建议调大到16MB以上。
调优命令示例:
# 临时生效
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_fin_timeout=15
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
# 永久生效(写入/etc/sysctl.conf)
echo "net.ipv4.tcp_tw_reuse = 1" >> /etc/sysctl.conf
echo "net.ipv4.tcp_fin_timeout = 15" >> /etc/sysctl.conf
sysctl -p
4.2 网卡多队列配置:让CPU不再排队
传统网卡只有一个队列,所有中断都打到同一个CPU核心上。高吞吐时,那个核心直接跑满,其他核心在围观。说白了,就是资源浪费。
网卡多队列(RSS / RPS)把中断分散到多个CPU核心,实现并行处理。我测试过,开启多队列后,吞吐量能提升30%-50%。
4.2.1 检查当前队列数
# 查看网卡支持的最大队列数
ethtool -l eth0
# 查看当前生效的队列数
ethtool -g eth0
4.2.2 配置多队列
如果硬件支持,直接设置:
# 设置队列数为CPU核心数(假设是8核)
ethtool -L eth0 combined 8
硬件不支持?别急,用RPS(Receive Packet Steering)软件模拟:
# 为每个队列设置CPU亲和性
echo "f" > /sys/class/net/eth0/queues/rx-0/rps_cpus
echo "f" > /sys/class/net/eth0/queues/rx-1/rps_cpus
个人经验: 队列数最好等于物理CPU核心数,不要超过。超了反而因为上下文切换导致性能下降。我习惯用 lscpu 先确认核心拓扑。
4.3 巨型帧设置:一次多拉快跑
标准以太网帧最大1518字节,其中有效载荷只有1460字节左右。巨型帧(Jumbo Frame)把MTU提到9000字节,有效载荷能到8960字节。
你想想看,传输1GB数据,标准帧要拆成约68万个包,巨型帧只要约11万个。包头开销少了,CPU中断也少了。
4.3.1 设置方法
# 临时设置MTU为9000
ifconfig eth0 mtu 9000
# 永久设置(CentOS/RHEL)
echo "MTU=9000" >> /etc/sysconfig/network-scripts/ifcfg-eth0
# 永久设置(Ubuntu)
echo "mtu 9000" >> /etc/network/interfaces
4.3.2 注意事项
- 全路径支持:从源端到目的端,所有交换机、路由器都必须支持巨型帧。我曾经在项目中只配了服务器端,结果中间交换机不支持,导致丢包严重。
- 延迟敏感场景慎用:巨型帧会增加单包传输时间,对实时性要求高的场景(如高频交易)反而有害。
- 测试方法:用
ping -M do -s 8972测试路径MTU,如果通说明支持。
最佳实践: 内网吞吐测试,巨型帧几乎是必开的。但公网环境别用,互联网设备大多不支持。我一般在内网压测集群里统一设置MTU 9000,配合多队列和TCP参数调优,效果立竿见影。
4.4 知识体系总览
下面这张图,把本章三个核心模块的关系串起来了:
4.5 调优验证:别光调不测
参数改完了,怎么知道有没有用?我一般用这三板斧:
- netstat -s:查看TCP重传率、丢包率。重传率超过0.1%就要警惕。
- sar -n DEV 1:实时监控网卡吞吐量和错误包。
- iperf3:双向打流测试,对比调优前后的吞吐差异。
我的习惯: 每次只改一个参数,测完再改下一个。这样出了问题能快速回滚。别一次性全改,否则出了问题你都不知道是哪个参数惹的祸。
网络调优不是玄学,是科学。参数摆在那里,效果测出来就知道。把这章的内容吃透,你的吞吐测试至少能少踩一半的坑。