找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

979

积分

0

好友

111

主题
发表于 3 天前 | 查看: 7| 回复: 0

本刊编辑仍记得安装第一块以太网适配器的情景。当时,DEC公司耗费大量工程资源,才将设备集成到近一平方米的板卡上,以支持10Mbps的传输速率。如今,网络速度已跃升至10Gbps,但支持高速适配器依然是重大挑战,原因已截然不同。在2009年的日本Linux研讨会上,Herbert Xu深入探讨了这些挑战以及Linux的应对之策。

部分问题根源在于,10G以太网本质上仍是传统以太网。虽然这能减少系统其他部分的改动负担,但以太网作为一项古老技术,背负着沉重的历史包袱,其中最突出的就是1500字节的最大传输单元(MTU)限制。由于数据包大小受限,一条满速的10G链路每秒需处理超过80万个数据包。与10Mbps时代相比,数据包数量暴增了三个数量级,而CPU性能的提升却未能同步跟上。因此,处理单个数据包可用的CPU时间被急剧压缩,这给网络子系统带来了巨大压力,必须千方百计降低单包处理开销。

(诚然,多核CPU的发展弥补了单核性能的不足,但Herbert的演讲聚焦于单CPU性能优化。原因有二:任何性能优化都应让单处理器系统受益;且将单个适配器的工作负载分配到多个CPU本身也是一项挑战。)

鉴于单包开销至关重要,一个自然的想法是提高MTU。这确实可行,“巨型帧”机制支持最大9KB的数据包。然而,Herbert指出,问题在于“互联网的现状”。我们关注的大多数连接都需穿越互联网,而路径的MTU受限于整条链路中的最小值,该值有时甚至低于1500字节。尽管存在基于协议的路径MTU发现机制,但在复杂的互联网环境中往往失效,许多防火墙设置会阻断相关探测。因此,巨型帧虽适用于局域网,但在广域网上我们仍被束缚在1500字节的MTU上。

既然无法使用更大的真实MTU,我们可以退而求其次:假装在使用更大的MTU。多年来,Linux一直支持具备“TCP分段卸载”(TSO)功能的网络适配器。内核可以为此类适配器准备超大(如64KB)的待发送数据包,由网卡在传输时将其分割成符合标准的小包。这能将内核处理开销降低高达40倍。Linux对TSO的支持已相当完善,对于以发送数据为主的系统(如Web服务器),TSO足以支撑10G网络满速运行。

实际上,内核还拥有更通用的“通用分段卸载”(GSO)机制,它不局限于TCP。事实证明,即使在驱动层模拟实现GSO,也能带来性能提升。但GSO仅作用于数据发送,不适用于接收。对于许多应用场景(如内容分发网络),这并无大碍,因其发送的数据量远大于接收量。然而,对于其他类型的工作负载(如数据库或流媒体服务器),接收数据包的开销与发送开销同等重要。

接收端的优化方案(大接收卸载,LRO)出现较晚,这不仅仅是因为早期用户更关注发送性能。优化接收更具挑战性,因为数据包接收是完全异步的事件,由外部控制,内核只能被动响应。相比之下,数据发送时内核处于主动控制地位,必要时可以对发送进程进行限流。

不过,LRO形式的解决方案已经出现,其思路与TSO异曲同工:在接收时合并多个传入的小数据包,从而大幅减少操作系统需要处理的数据包数量。这种合并可由驱动程序或硬件完成,即使在驱动层模拟LRO也能带来收益。Linux下的众多10G网卡驱动都已支持LRO。

然而,Herbert指出,LRO是一个存在缺陷的解决方案,根本问题在于它“将眼前的所有数据包都合并”。这种合并是有损的,如果传入数据包的头部存在重要差异,这些信息将在合并过程中丢失,从而引发一系列问题。例如,充当路由器的系统不应在数据包经过时更改其头部,LRO可能破坏这一点。它也可能完全破坏某些基于卫星的特殊连接,因为提供商为保障系统运行会对包头进行特殊处理。此外,桥接功能会失效,这是一个严重问题,因为大多数虚拟化设置都在主机与客户端之间使用虚拟网桥。尽管在这些场景下可以禁用LRO,但这些场景本身往往正是最需要性能优化的工作负载(如虚拟化网络)。

真正的解决方案是通用接收卸载(GRO)。在GRO机制下,数据包合并的标准被极大收紧:MAC头部必须完全一致,且仅允许极少数的TCP或IP头部字段存在差异。具体来说,允许变化的字段被严格限制为必然会不同的校验和,以及允许递增的IP标识字段。甚至连TCP时间戳也必须相同(由于时间戳字段分辨率较低,多个数据包拥有相同时间戳的情况并不罕见)。得益于这些严格的限制,合并后的数据包可以做到无损地重新分段。另一个好处是,重新分段操作可以直接复用现有的通用分段卸载(GSO)代码。

GRO的另一大优势在于,它不像LRO那样局限于TCP/IPv4协议。

GRO代码已被整合进2.6.29版本及之后的Linux内核,并获得了众多10G网卡驱动的支持。将驱动程序从LRO迁移至GRO相对简单。目前的主要障碍在于,一些新编写的驱动程序仍在沿用LRO的应用程序编程接口(API)。未来,一旦网络开发人员确信GRO功能完备且性能无损,LRO API可能会被彻底移除。

在问答环节,Herbert提到,针对1G网卡驱动的LRO优化工作并不多,因为当前CPU处理1G数据流通常游刃有余。但对于处理器较弱的嵌入式系统,此类优化可能仍有价值。关于内核在合并数据包前等待多久的问题,实际上并不需要专门的等待逻辑:现有的NAPI机制已经让驱动程序以轮询方式批量处理新数据包,GRO只需在NAPI轮询周期内执行合并即可。

展望未来,下一步可能是实现“基于通用流的合并”;甚至开始合并发往同一目的地的不同数据流,以形成更大的路由单元。UDP数据包的合并也已提上日程。此外,合并TCP确认(ACK)数据包也可能带来收益。这些ACK包体积很小但数量庞大(通常每两个数据报就对应一个ACK包)。网络优化技术可能会朝着意想不到的方向演进,但有一点是明确的:为了让Linux跟上硬件不断提速的步伐,网络开发人员的创造力永远不会枯竭。

Src

https://lwn.net/Articles/358910/




上一篇:React命令行开发框架Ink:GitHub Copilot等大厂AI工具背后的CLI构建利器
下一篇:LibrePods项目详解:在Android与Linux平台解锁AirPods完整硬件功能
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-17 16:09 , Processed in 0.122347 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表