第3章:网卡选型与硬件卸载:Intel XL710/E810网卡特性,以及LRO/GRO/GSO/TSO卸载技术

3.1 为什么网卡选型这么重要?

说实话,很多做网络优化的朋友,上来就调内核参数,改TCP栈,折腾半天效果不明显。我早年也犯过这个错。后来才明白——网卡选型是性能优化的起点。你选错了卡,后面再怎么调,天花板就在那儿。

Intel的XL710和E810,是我在数据中心项目里用得最多的两款。它们代表了两个时代:XL710是40G时代的标杆,E810则是100G时代的扛把子。今天我就把这两款卡的底裤扒干净,再聊聊那些硬件卸载技术到底怎么用。

3.2 Intel XL710:40G时代的常青树

XL710这卡,我2015年就开始用了。当时在做一个金融交易系统的网络优化,延迟要求极其苛刻。XL710给我的第一印象就是——

核心特性一览:

  • 支持40GbE和10GbE双模式
  • 内置Flow Director技术,支持RSS(接收端缩放)
  • 支持VMDq(虚拟机设备队列),虚拟化场景利器
  • 硬件支持VXLAN/NVGRE隧道卸载
  • 支持iWARP/RoCE v2 RDMA

XL710的Flow Director,说白了就是硬件级的流量分类器。它可以根据IP五元组,把流量精确分发到指定队列。我在项目中遇到过一个问题:某个业务线程总是被中断风暴打垮,后来用Flow Director把它的流量固定到单独队列,CPU使用率直接降了30%。

3.3 Intel E810:100G时代的性能猛兽

E810是Intel在100G时代的王牌。2020年我帮一个云厂商做网络升级,从40G换到100G,用的就是E810。这卡给我的感觉是——武装到了牙齿

特性 XL710 E810
最大速率 40GbE 100GbE
PCIe接口 PCIe 3.0 x8 PCIe 4.0 x16
ADQ(应用设备队列) 不支持 支持
动态设备个性化(DDP) 有限支持 全面支持
硬件时钟同步 IEEE 1588 IEEE 1588 + 增强PTP

E810最让我惊艳的是ADQ技术。你想想看,传统网卡处理流量是"先来后到",但有些关键业务需要优先处理。ADQ可以为特定应用预留队列和带宽。我帮一个视频直播平台调优时,用ADQ把推流流量单独隔离,卡顿率从2%降到了0.1%。

我的经验:E810的DDP功能可以动态加载不同的包处理流水线。比如你跑NVMe over Fabric,就加载NVMe的DDP包;跑存储,就加载iSCSI的。不用换卡,改个配置文件就行。这灵活性,XL710真比不了。

3.4 硬件卸载技术:把CPU解放出来

为什么要搞硬件卸载?说白了,CPU不是万能的。你让CPU去处理每一个网络包的分段、重组、校验和,那它哪还有精力跑业务?硬件卸载就是把这些脏活累活交给网卡。

3.5 TSO(TCP分段卸载)

TSO是我用得最多的卸载技术。它的原理很简单:应用程序发送一个大包(比如64KB),网卡硬件自动把它切成MTU大小的段(通常是1500字节)

# 查看TSO是否开启
ethtool -k eth0 | grep tcp-segmentation-offload
tcp-segmentation-offload: on

# 开启TSO
ethtool -K eth0 tso on

# 关闭TSO(一般不建议)
ethtool -K eth0 tso off

我曾经在一个文件传输服务上做过对比测试:开启TSO时,CPU利用率约15%;关闭TSO后,CPU直接飙到60%以上。为什么?因为每个TCP段都要CPU去切分,中断次数暴增。

注意:TSO不是万能的。如果你的网卡不支持TSO校验和卸载,或者驱动有bug,开启TSO反而会导致数据损坏。我遇到过一起案例:某款老网卡开启TSO后,大文件传输偶尔出现CRC错误,关了就好了。所以,新卡用TSO,老卡慎用

3.6 GSO(通用分段卸载)

GSO是TSO的软件版本。当网卡不支持TSO时,内核会在协议栈里做分段。GSO的好处是:对上层应用透明,无论网卡是否支持,都能享受大包发送的好处

GSO和TSO的关系,你可以这么理解:TSO是硬件卸载,GSO是软件卸载。如果网卡支持TSO,GSO会自动让路给TSO。如果网卡不支持,GSO就在内核里把活干了。

# 查看GSO状态
ethtool -k eth0 | grep generic-segmentation-offload
generic-segmentation-offload: on

3.7 LRO(大接收卸载)

LRO是接收方向的"反TSO"。它把多个小包合并成一个大包,再交给上层协议栈。这样能减少协议栈的处理次数,降低CPU开销。

但LRO有个坑——它破坏了TCP的拥塞控制。因为LRO合并包时,会丢失一些ACK信息,导致TCP对网络拥塞的判断不准确。我在一个长肥网络(高带宽高延迟)的项目中,开启LRO后吞吐量反而下降了。后来查资料才发现,LRO在这种场景下会干扰TCP的窗口增长算法。

我的建议:除非你的网络环境非常干净(无丢包、低延迟),否则别开LRO。用GRO代替它。

3.8 GRO(通用接收卸载)

GRO是LRO的改进版。它也在接收方向合并小包,但合并逻辑更智能——会考虑TCP的序列号和ACK信息,不会破坏拥塞控制。

GRO现在是Linux内核的默认配置。我几乎在所有服务器上都开着它。你想想看,一个10Gbps的链路,每秒可能有几十万个包。如果不合并,CPU光处理包就要累死。

# 查看GRO状态
ethtool -k eth0 | grep generic-receive-offload
generic-receive-offload: on

# 调整GRO合并超时时间(单位:纳秒)
echo 50000 > /sys/class/net/eth0/gro_flush_timeout

调优技巧:对于延迟敏感的业务(如高频交易),可以把gro_flush_timeout设小一点(比如10000纳秒),让包尽快上送。对于吞吐量优先的业务(如文件服务器),可以设大一点(比如100000纳秒),让合并更充分。

3.9 卸载技术的协同工作

这些卸载技术不是孤立的。它们在内核网络栈中协同工作:

  1. 发送路径:应用调用send() → 内核构建SKB → GSO/TSO处理 → 网卡发送
  2. 接收路径:网卡接收 → GRO/LRO合并 → 内核协议栈 → 应用recv()
  3. 校验和卸载:发送时网卡计算TCP/UDP校验和,接收时网卡验证校验和

我见过最离谱的配置是:有人同时开启了TSO和LRO,但关闭了GRO和GSO。结果发送走硬件卸载,接收走软件合并,两边不对称,性能反而比全关还差。所以我的原则是——要么全开,要么全关,别搞混搭

3.10 选型建议:XL710还是E810?

最后给点实在的建议:

  • 预算有限,40G够用:选XL710。它成熟稳定,驱动完善,社区支持好。我手头还有几块XL710在跑生产,三年没出过问题。
  • 追求极致性能,100G起步:选E810。ADQ和DDP这两个特性,在云原生和虚拟化场景下优势明显。
  • RDMA场景:两款都支持,但E810的RoCE v2性能更好,延迟更低。
  • 虚拟化场景:E810的ADQ可以给每个虚拟机分配独立队列,避免"吵闹的邻居"问题。

嗯,网卡选型和硬件卸载就聊到这儿。下一章我们深入内核,看看协议栈到底是怎么处理这些卸载请求的。到时候我会带大家读一段内核源码,保证让你对网络栈的理解上一个台阶。