上周刚把一张网讯WX1860AL4四口千兆网卡装进服务器,兴冲冲地拿iperf3打流,结果傻眼了:服务端到客户端怎么跑都只有480Mbps左右,离千兆Line Rate差了整整一半。第一反应是网卡有问题,退换货申请都写到一半了。但在折腾了一整晚、翻了无数资料之后,我意识到问题几乎全出在测试链路和参数配置上,网卡本身反而是最后排查下来最无辜的那个。
如果你也遇到WX1860AL4的iperf3实测性能不达标,先不要急着下"网卡垃圾"的结论。这篇文章我把排障过程完整拆开,按五个最常见的原因逐个过一遍,每一步都给出实际命令和判断标准,保证你照着操作能找到自己环境里的症结。
1. 测试环境与基线判定:先确认问题在收包端还是发包端
先说清楚我的测试环境,否则后面的数据和原因都没参考意义。服务器是一台普通的x86平台,插了WX1860AL4其中一个千兆口,接对端PC的板载千兆网卡,中间用一根超六类网线直连。服务器操作系统是Linux,内核版本5.15,iperf3版本3.9。
1.1 网卡协商状态确认
任何iperf3测试之前,第一步永远是确认物理链路协商状态。千兆网卡如果协商到百兆,后面所有测试都是白做。用ethtool看一眼:
ethtool enp3s0正常输出里关键字段是:
Speed: 1000Mb/s Duplex: Full如果这里显示的是100Mb/s甚至10Mb/s,先别管iperf3,去查网线、交换机端口和对端网卡设置。我这边的两根网线里有一根就是劣质五类线,插上去只能协商到100M,换了超六类才恢复正常。这个坑不排除,后面所有原因分析都是空中楼阁。
1.2 "不达标"的判定基线
很多朋友对"达标"的预期有误解。千兆以太网的物理层速率是1000Mbps,但TCP/IP协议栈有开销,所以实测TCP吞吐量的理论极限大约在940Mbps左右。换句话说,iperf3跑到930-940Mbps,这张千兆网卡就是满血状态;只有像我的环境这样跑到500Mbps上下,甚至更低,才需要考虑性能问题。
还有个更高效的判定手段:UDP打流。因为UDP头开销远小于TCP,用UDP可以逼近线速,把"TCP协议栈性能问题"和"物理链路/网卡硬件问题"快速分开。先用一条命令验证网卡的极限带宽:
iperf3 -u -c 192.168.1.10 -b 1000M -t 30如果UDP能跑到950Mbps以上且丢包率很低,基本宣告网卡和物理链路没问题,真正的瓶颈在TCP参数或CPU处理能力上。这个判断顺序帮我省了很多无用功。
1.3 双向测试看不对称性
别忘了做反向测试。iperf3客户端加-R参数,或者把服务器和客户端角色互换,测出来的两个方向数据非常关键。我当时的测试结果就呈现出明显的不对称:
| 测试方向 | 单线程TCP吞吐 | UDP线速测试 |
|---|---|---|
| 服务器到PC | 480Mbps | 950Mbps无丢包 |
| PC到服务器 | 920Mbps | 950Mbps无丢包 |
UDP能跑满、TCP一个方向正常一个方向减半,这种组合基本把嫌疑锁定在驱动、中断和CPU调度层面,而不是网卡硬件本身。方向不对称意味着问题更可能出在服务器这一侧的收报链路。后面的排查就是围绕这个结论展开的。
2. 第一个原因:驱动和固件版本对不上,性能直接腰斩
WX1860AL4这类网卡在Linux下能不能发挥全部性能,驱动版本是最大的变量。官方驱动和个人编译的内核模块、发行版自带驱动之间,性能差异可能大到超出你的想象。
2.1 症状描述与判断依据
驱动导致的问题有个很典型的表现:UDP打流能跑满线速,但TCP单线程吞吐量始终徘徊在500Mbps上下,而且CPU某核心跑得很高,中断数多到不正常。这是因为老版本驱动或内核通用驱动对多队列支持不完整,收包全部压在一个CPU核心上,单核处理不过来,TCP就上不去。
确认驱动信息用这条命令:
ethtool -i enp3s0重点关注driver和version字段。WX1860AL4对应的驱动模块是ngbe,如果显示的是内核自带的通用驱动,或者版本号非常旧、没有针对WX1860AL4的固件配套信息,优先怀疑驱动。后来我找到的官方驱动包里,README明确写了支持的硬件版本和固件适配要求,Step 1就是要求先确认固件版本与驱动版本匹配。
2.2 驱动升级的具体操作路径
我的处理方式是去官网下载最新驱动源码自行编译安装。步骤不算复杂,但有几个细节必须提醒你:
# 安装编译依赖 sudo apt install build-essential linux-headers-$(uname -r) # 解压驱动源码 tar -zxvf WX1860AL4_driver.tar.gz cd WX1860AL4_driver/src # 编译并安装 make clean && make sudo make install # 重新加载驱动 sudo modprobe -r ngbe sudo modprobe ngbe编译驱动前务必确认内核头文件版本和当前内核完全一致,否则模块加载会报错。另外注意一个容易踩的坑:如果你的网卡之前被系统自动分配了固定的设备名(比如enp3s0),模块重新加载后设备名可能变化,测试命令里的接口名记得顺手更新。
驱动更新完之后,再跑一次iperf3 TCP单线程测试。我的数据从480Mbps提高到了720Mbps左右,有提升,但还没到理想值。说明驱动只是原因之一,后面还有别的坑。
3. 第二个原因:iperf3默认参数没吃满千兆,单流和窗口是硬伤
很多人拿到iperf3就直接iperf3 -c 192.168.1.10,啥参数也不加。这对于千兆局域网测试来说,往往测不出网卡的真实水平。iperf3的默认配置是为通用场景设计的,不会主动帮你把吞吐压满。
3.1 单线程与多线程的性能差距
TCP单流吞吐量受限于单个CPU核心处理网络中断和数据拷贝的能力,这是TCP/IP协议栈的固有限制,跟网卡好坏关系不大。千兆局域网里,单核CPU如果主频不高,处理一个TCP流可能就到600-700Mbps。这时候不是网卡不行,是CPU忙不过来。
验证办法很简单,用-P参数起多个并行流:
iperf3 -c 192.168.1.10 -t 30 -P 4-P 4表示同时开4个TCP连接。理论上每个连接分担一部分负载,总吞吐量会明显上升。我实测单线程从480Mbps变成4线程后的数据直接到920Mbps,CPU使用率反而降下来了。这个结果足以证明:网卡和链路没有问题,问题出在单线程处理能力上。
3.2 窗口大小、测试时长和缓冲区的影响
socket缓冲区大小也要关注,尤其当网络延迟略有波动的时候。用-w参数显式指定窗口:
iperf3 -c 192.168.1.10 -t 30 -w 2M局域网内部RTT通常只有零点几毫秒,带宽延迟积很小,理论上默认窗口就够。但如果你对端是虚拟机、经过交换机或跨越较长链路,RTT可能上升到几毫秒甚至几十毫秒,这时候默认窗口就不够了。设置一个合理的大窗口能显著改善吞吐。
另外测试时长别用默认的10秒。网卡和驱动存在一个"预热"过程,TCP拥塞窗口要慢慢增长,10秒可能还没到稳态测试就结束了。建议至少-t 30,我这个场景保持30-60秒测出来的数据更稳定。
最后说下UDP打流参数。如果想测网卡会不会丢包,可以加大发送缓冲:
iperf3 -u -c 192.168.1.10 -b 1000M -l 1400 -t 30-b 1000M强行按1000Mbps速率发包,-l 1400设置UDP负载大小。输出的丢包率如果低于0.01%,说明网卡接收能力没问题,可以继续往下排查。
参数调完之后,我再测单线程TCP,依然只有750Mbps左右,但多线程已经能到940Mbps。那么问题来了:为什么单线程还是上不去?这就轮到系统层面的背锅侠们出场了。
4. 第三个原因:PCIe协商、多队列与中断绑定在系统层悄悄拖后腿
硬件和参数都没问题时,系统层可能藏着最大的隐形杀手:PCIe链路协商异常、网卡多队列没开启、中断没有绑定到合适的CPU核心。这些细节不影响"网卡能不能用",但严重影响"网卡能不能跑满"。
4.1 先用lspci确认PCIe链路状态
WX1860AL4是PCIe接口的四口网卡,所有端口共享PCIe总线带宽。如果链路宽度或速率没有协商到预期值,多端口同时打流或者单端口高负载时都可能出现带宽瓶颈。查看方法:
lspci | grep -i ethernet lspci -vvv -s 03:00.0 | grep -Ei "lnkcap|lnksta"第二行输出里重点看LnkSta字段,它显示当前实际协商的链路速率和宽度。例如Speed 5GT/s, Width x2代表运行在PCIe 2.0 x2模式。如果发现宽度只有x1、速率明显低于该网卡支持的最高规格,说明插槽或者BIOS设置有问题,需要换个插槽试试。
这里有个容易被忽视的场景:四口网卡如果四个口同时跑满千兆,总流量可能达到4000Mbps,就算PCIe链路速率正常,单个口也会和相邻口争抢总线带宽。实测时如果只测一个口达标,不代表四个口同时满负载也达标。有条件的话,用两条iperf3流同时打两个口,观察两边的吞吐是否互相影响。
4.2 多队列与中断绑定实战
现代网卡几乎都支持多队列(RSS),也就是把收包中断分散到多个CPU核心,避免单核过载。先查一下当前队列数:
ethtool -l enp3s0如果Combined队列数是1,说明多队列没开启。把它调到网卡支持的最大值:
ethtool -L enp3s0 combined 4注意这个设置在某些驱动下重启后会失效,要写入系统配置。设置完成后查看中断分布:
cat /proc/interrupts | grep enp3s0正常情况下你会发现不同队列的中断号对应不同的CPU核心。如果全部落在同一个CPU上,需要手动绑核。中断绑定涉及具体的IRQ号,操作方式大致是:
# 查看enp3s0各队列的中断号 cat /proc/interrupts | grep enp3s0 # 将某个中断号绑定到CPU0 echo 1 > /proc/irq/85/smp_affinity # 绑定到CPU1 echo 2 > /proc/irq/86/smp_affinitysmp_affinity用十六进制bitmask表示CPU集合,1代表CPU0,2代表CPU1,3代表CPU0和CPU1。对于那些原本不热衷折腾服务器的人,装一个irqbalance服务自动分配中断到各核心也是可以的,但手动绑定在关键性能测试场景下往往更可控。
把多队列开启、中断分散到不同核心之后,我再次跑单线程iperf3,这次吞吐量终于从750Mbps爬到了900Mbps以上。说实话这个结果已经能接受了,但要填满那个"最后5%"的缺口,还得继续往下查。
5. 第四个原因:对端设备、线缆质量与混杂模式的隐藏干扰
排查到这一步,网卡这边能优化的几乎都试过了。但iperf3测试结果从来不是单端决定的,对端设备、中间链路和网卡工作模式都可能成为隐藏瓶颈。很多人在服务器端折腾半天,忘了问题可能出在对面那台PC或者一根质量不佳的网线上。
5.1 网线、交换机和端口协商的坑
先做物理层检查。直连场景下,网线质量是最大的变量。我之前遇到过一根看起来没有任何损伤的网线,实际内部有一对线断裂,导致协商结果是千兆但重传率极高,吞吐量只有正常的一半。判断方式很简单:
- 看ethtool的协商结果是否稳定在1000Mb/s Full
- 看网卡的错误计数,用
ethtool -S enp3s0 | grep -i err,重点看rx_errors、tx_errors、rx_crc_errors - 交换场景下检查交换机端口是否开启了限速或流控(Pause Frame)
如果你在iperf3测试时发现吞吐量忽高忽低,一会儿900Mbps一会儿600Mbps,大概率存在物理层重传问题。换一根高质量六类线重新测试,是成本最低的排障手段。
5.2 混杂模式、监听工具与虚拟化环境的开销
这个原因非常隐蔽,如果你测试时无意识开着抓包工具,或者网卡处于混杂模式(promiscuous mode),性能会受到明显拖累。因为混杂模式下网卡驱动要把所有收到的报文都交给上层处理,即使不是发给本机的帧也要过一遍,CPU开销直线上升。
检查网卡是否处于混杂模式:
ip link show enp3s0如果输出里出现PROMISC字样,说明混杂模式已开启。关掉它的方法:
ip link set enp3s0 promisc off如果是在做安全分析时需要监听模式跑测试,务必知道这个模式会压低iperf3的成绩,别把抓包环境和正常业务混为一谈。
虚拟化环境同样需要提醒一句。如果你拿着iperf3在虚拟机里实测通过WX1860AL4做SR-IOV或PCIe直通后的虚拟网卡,要分清楚性能瓶颈在虚拟交换机还是物理网卡。我建议测试分两层:先在宿主机上直接跑一次iperf3物理网卡基线,再进虚拟机测试,对比两者差异,才能判断虚拟化层是否有问题。
5.3 对端网卡驱动的干扰
还有一个容易忽略的点:对端网卡的驱动或参数也可能成为瓶颈。我一开始以为WX1860AL4单线程跑不动,后来发现对端PC用的USB转千兆网卡,本身单线程性能就拉胯,换个板载PCIe千兆口之后,服务器端单线程直接提升到910Mbps。iperf3的结果是两端协议栈共同作用的结果,排查问题别只盯着一边看。
物理链路层面排除干净之后,还剩下最后一个影响单线程成绩的因素,就是协议栈参数和CPU节能策略。
6. 第五个原因:TCP协议栈参数和CPU节能策略,最后一道闸
如果上面四个原因都排除了,单线程TCP吞吐还是差那么一口气,比如总在900Mbps以下上不去,或者突发性能波动明显,基本就是TCP协议栈参数和CPU节能策略在作怪。这两个因素平时影响不大,但追求极限性能时就会显现。
6.1 需要调整的内核参数清单
Linux内核的TCP缓冲区默认值偏保守,适合大多数通用场景,但不适合千兆局域网的大吞吐测试。建议临时调整以下参数:
sysctl -w net.core.rmem_max=16777216 sysctl -w net.core.wmem_max=16777216 sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216" sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216" sysctl -w net.core.netdev_max_backlog=16384第一组参数把收发缓冲区上限提高到16MB,避免在大窗口场景下被内核限制截断;第二组参数让TCP滑动窗口能够增长到足够大;netdev_max_backlog是网卡接收队列的积压长度,当突发流量到来时能容纳更多待处理报文,降低丢包概率。实际生效范围在当前运行时环境,确认效果没问题后再写入/etc/sysctl.conf持久化。
另外值得一提的技巧是网卡的中断合并(coalescing)参数。ethtool -c enp3s0可以查看当前设置,rx-usecs表示收包后延时多少微秒再触发中断。数值太大延迟变高,太小则CPU频繁被中断。千兆预测高吞吐场景下,可以尝试调小:
ethtool -C enp3s0 rx-usecs 4 tx-usecs 4这个值要根据你的CPU和负载反复测几次,找到一个吞吐和延迟都满意的平衡点。我自己的环境从默认的几十微秒调小到4微秒后,单线程TCP吞吐从870Mbps提升到了940Mbps,效果显著。
6.2 关闭CPU节能与最终验证结果
CPU节能策略是最后一个往往被忽略的变量。服务器为了省电,默认可能开启C-States深度节能,CPU在低频和休眠状态之间频繁切换。网络中断处理需要CPU快速响应,如果CPU刚从深度睡眠唤醒,前几百微秒处于低频状态,处理能力跟不上,TCP窗口增长就会受影响。
最简单的验证方式是临时把CPU调到performance模式:
cpupower frequency-set -g performance这个操作只是运行时生效,重启后恢复默认。如果性能有明显改善,可以考虑在BIOS里关闭C-States或者调高电源管理策略。另一个相关的点是PCIe的ASPM电源管理,某些主板默认开启后,会降低PCIe链路功耗但增加延迟。查一下:
lspci -vvv -s 03:00.0 | grep -i ASPM如果LnkSta里的ASPM状态不是Disabled,可以用内核参数pcie_aspm=off或者BIOS选项强制关闭。对于追求极限吞吐的环境,ASPM带来的省电意义远小于性能损耗。
所有调整做完之后,我最终跑出来的数据是:
| 测试项 | 初始值 | 最终值 |
|---|---|---|
| TCP单线程 服务器到PC | 480Mbps | 941Mbps |
| TCP单线程 PC到服务器 | 920Mbps | 938Mbps |
| TCP多线程 4条流 | 930Mbps | 941Mbps |
| UDP 1000M线速 | 950Mbps无丢包 | 950Mbps无丢包 |
从480Mbps到941Mbps,整个过程中真正属于网卡硬件故障的排查时间其实为零。每一分提升都来自驱动、系统参数和测试方法的修正。这时候再回头看标题里的"性能不达标",答案已经很清楚了:更多时候是网卡周围的环境没有配套到位。
最后分享一个我个人的小经验:遇到网卡性能不达标,先UDP打流排除硬件,再换多线程确认CPU能力,然后逐项检查驱动、PCIe链路和系统中断,最后才去调协议栈。这个顺序能让你少走很多弯路。另外测试环境务必保持干净,关掉抓包工具,用-R做双向测试,记录数据时把两端信息一起记下,这些基本功会让排障效率倍增。