LWN: 让 TCP packet size 大大增加!

关注了就能看到更多这么棒的文章哦~

Going big with TCP packets

By Jonathan Corbet
February 14, 2022
DeepL assisted translation
https://lwn.net/Articles/884104/

计算领域的大多数组件都跟网络硬件一样,会随着时间的推移稳步演进。事实上,今天的高端的网络接口设备的数据传输速度往往比它们所连接的系统能对数据进行处理的速度还要快。网络开发人员多年来一直在努力提高网络子系统中的可扩展性;目前就有 Eric Dumazet 和 Coco Li 的 BIG TCP 这组 patch set 是与此相关的。BIG TCP 并不适合所有人,但它有可能在某些情况下大幅提高网络性能。

举例来说,如果你希望完全利用好一个 100Gb/s 的网络适配器,那么正如网络开发人员 Jesper Brouer 在 2015 年所描述的那样,如果仍然按我们长期以来一直在用的 1538 字节作为数据包的最大 size,那么网卡全速运行时就意味着每秒要处理超过 800 万个数据包。按这个速度来算的话,CPU 处理每个数据包仅有大约 120 纳秒的时间,这个时间非常短了,只要发生一次 cache miss 就可能会耗费这么多时间。

不过,如果减少数据包的数量的话,情况就会好转。要做到这一点仅仅需要增大数据包的 size 就好。因此,高性能的网络设施,尤其是那些把全部设备都当作一个网络单元来统一协作的局域网,通常都会使用较大的数据包 size。在适当配置之后就可以使用高达 64KB 的数据包 size,就能大大改善这种情况。但是,在那些需要处理 MB 级别或 GB 级别的数据(还有更多的,毕竟猫咪视频也都一直在变大)的环境中,系统仍然有大量的数据包需要处理。

数据包数量太多会导致影响很多方面的性能。每一个流经此系统的数据包都有显著的固定开销。每个数据包都必须通过网络堆栈的处理,从上层协议层到网络接口的设备驱动(或按此路径返回),找到自己该去哪里。更多的数据包就意味着来自网络适配器的更多中断。在内核中用来表示数据包的 sk_buff 结构("SKB")是一个庞大复杂的结构,因为它必须能够支持任何有可能会在使用的网络功能。这就导致了每个数据包都使用大量内存,以及提高了相关的内存管理成本。因此,很希望能够以更少、且更大的数据包为单位来移动数据,至少对于某些类型的应用来说是希望这样的。

IP 数据包的长度存储在 IP 头中;对于 IPv4 和 IPv6,该长度存放在一个 16 bit 的字段中,将数据包的最大尺寸限制在了 64KB。在设计这些协议的时候,一个 64KB 的数据包在当时的骨干互联网链路(backbone internet links)上可能需要很多秒的时间来传输,所以当时看起来已经是一个非常大的数字了;其实那个时代任何一个有理性的人都不会使用 64KB 来放单个数据包的。但是,时代变了,64KB 现在看起来是一个令人沮丧的过低限制。

并不是最近才认识到这个问题的:在 1999 年通过的 RFC 2675 中可以找到一个解决方案(至少对 IPv6 而言)。IPv6 规范允许放置带有额外信息的 "hop-by-hop" header 头;顾名思义,hop-by-hop header 会用来在两个直接连接起来的系统之间进行 option 选项的交流。RFC 2675 对协议进行了一些调整,使得可能支持大型数据包了。为了发送一个 "jumbo" 数据包,系统必须将(16 位的)IP payload length 字段设置为零,并添加一个包含了真正的 payload length 的 hop-by-hop header。这个 hop-by-hop header 中的 length 字段是 32 位的,这意味着一个 jumbo packet 就可以包含多达 4GB 的数据了,这对每个人来说肯定是足够了。

BIG TCP 这组 patch set 添加了相关的代码逻辑,这样就能在连接的最大传输单元(MTU)被设置得足够高时可以生成和接受 jumbo packet。不出所料,这里有许多细节需要处理,以便能让其真正工作起来。其中一个更重要的问题是,这一系列数据包可能就不是存放在物理连续的内存中了,因为有时候很难分配到想要的连续内存空间。对于 zero-copy 操作来说,buffer 是来自用户空间的,这些数据包必定是分散在物理内存中各个地方的。因此,数据包经常是一组 fragment 片段,每个片段可能最短会是一个 4KB 的 page;网络接口在处理数据传输时会负责将数据包从 fragment 片段组合起来(或在收到网络数据时分割成多个 fragment)。

目前的内核里将一个 SKB 中存储的 fragment 数量限制在了 17 个,这足以将一个 64KB 的数据包用多个 4KB 的小块内存拼接起来。但是在使用更大 size 的数据包的时候,这个限制显然会导致干扰了,所以 patch set 提高了 fragment 的最大数量(提升到 45)。但是,正如 Alexander Duyck 所指出的,许多网络接口驱动程序对一个数据包可能被分割成的最大 fragment 数量在代码中就想当然地处理了。他说,在没有修复驱动程序的情况下提升这个上限值可能会导致性能倒退,甚至导致硬件不可用了。

经过一些讨论,Dumazet 建议通过增加一个配置选项来解决这个问题,用它来控制各个数据包所允许的最大 fragment 数量。这对那些自己会构建自己的内核的网站来说足够用了,那些可能会使用这个功能的潜在用户相对来说可能会配置成这样。但是,这对发行版提供商来说帮助不大,他们必须要为他们的所有用户来决定这个选项的值。

无论如何,都会有许多驱动程序需要进行更新,才能处理 jumbo packet。现代网络接口还会进行 segmentation offloading,意味着创建一个数据包的大部分工作是由接口硬件本身来完成的。要想让 segmentation offloading 跟 jumbo packet 能配合起来,还会需要进行少量调整,因此在 patch set 中也修改了一些驱动程序的代码。

还有一个小问题与 RFC 2675 hop-by-hop header 的位置有关。根据 IPv6 标准,这些头被放在了 IP 头之后,这可能会使那些 "想当然地认为" TCP 头是在在数据包中的 IP 头之后紧跟着的位置的软件代码失效。tcpdump 工具在这方面就有一些问题,另外,似乎在满天飞的 BPF 程序中也有不少是含有这种假设的。因此这个原因,即使底层硬件和链路可以处理这些数据包,我们仍然需要把 jumbo packet 处理功能默认关闭掉。

Dumazet 在发布补丁的同时还包括一些简单基准测试的结果。使用 185 KB 字节的数据包 size 之后,网络吞吐量增加了近 50%,同时也大大减少了往返延迟(round-trip latency)。因此,BIG TCP 似乎是一个很有价值的可选功能,至少在那些使用了高速链接并能可靠地传送大数据包的环境中(例如数据中心)是这样的。如果未来的猫咪视频能加载得更快一些了,也许就是得益于咱们的 BIG TCP 呢。

更多细节请参见 Dumazet 在 2021 年 Netdev 上的演讲。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

2cee9d6279fdaa23cf8de92a937acc81.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值