专栏首页LINUX阅码场怎么提高网络应用性能?让DPDK GRO和GSO来帮你!

怎么提高网络应用性能?让DPDK GRO和GSO来帮你!

背景

目前,有大量的网络应用在处理数据包的时候只需要处理数据包头,而不会操作数据负载部分,例如防火墙、TCP/IP协议栈和软件交换机。对这类网络应用而言, 包头处理产生的开销(称为“per-packet overhead”)占了整体开销的大部分。因此,如何减少包头处理开销是优化这类应用性能的关键。

减少包头处理开销最直接的方法:减少数据包数量

如何减少包数量?

  • 增大Maximum Transmission Unit (MTU)。在数据量一定的情况下,使用大MTU的数据包可携带更多数据,从而减少了包的总量。但MTU值依赖于物理链路,我们无法保证数据包经过的所有链路均使用大MTU。
  • 利用网卡特性:Large Receive Offload (LRO),UDP Fragmentation Offload (UFO)和TCP Segmentation Offload (TSO)。如图1所示,LRO将从物理链路收到的TCP包(如1500B)合并为长度更长的TCP包(如64KB);UFO和TSO将上层应用发送的长数据负载的UDP和TCP包(如64KB)拆分成长度更短的数据包(如1500B),以满足物理链路的MTU限制。通过在网卡上进行包合并和拆分,在不需要任何CPU开销的情况下,上层应用就可以处理数量大大减少的大包。然而,LRO、TSO和UFO通常只能处理TCP和UDP包,而且并非所有的网卡都支持这些特性。
  • 软件包合并 (Generic Receive Offload,GRO)和包拆分 (Generic Segmentation Offload,GSO)。与前两种方法相比,GRO和GSO有两个优点:第一,不依赖于物理链路和网卡;第二,能够支持更多的协议类型,如VxLAN和GRE。

图1. LRO、UFO和TSO工作原理

为了帮助基于DPDK的应用程序(如Open vSwitch)减少包头处理开销,DPDK分别于17.08和17.11支持了GRO和GSO。如图2所示, GRO和GSO是DPDK中的两个用户库,应用程序直接调用它们进行包合并和分片。

图2. DPDK GRO和DPDK GSO

1

GRO库和GSO库结构

图3描绘了GRO库和GSO库的结构。根据数据包类型,GRO库定义了不同的GRO类型。每一种GRO类型负责合并一种类型的数据包,如TCP/IPv4 GRO处理TCP/IPv4数据包。同样的,GSO库也定义了不同的GSO类型。GRO库和GSO库分别根据MBUF的packet_type域和ol_flags域将输入的数据包交给对应的GRO和GSO类型处理。

图3. GRO库和GSO库的框架

2

如何使用GRO库和GSO库?

使用GRO和GSO库十分简单。如图4所示,只需要调用一个函数便可以对包进行合并和分片。

图4. 代码示例

为了支持不同的用户场景,GRO库提供了两组API:轻量模式API和重量模式API,如图5所示。轻量模式API应用于需要快速合并少量数据包的场景,而重量模式API则用于需要细粒度地控制合包并需要合并大量数据包的场景。

图5. 轻量模式API和重量模式API

3

DPDK GRO的合包算法

算法挑战

  • 在高速的网络环境下,高开销的合包算法很可能会导致网卡丢包。
  • 包乱序(“Packet Reordering”)增加了合包难度。例如Linux GRO无法合并乱序的数据包。

这就要求DPDK GRO的合包算法:

  • 足够轻量以适应高速的网络环境
  • 能够合并乱序包

基于Key的合包算法

为解决上述两点挑战,DPDK GRO采用基于Key的合包算法,其流程如图6所示。对新到的数据包,首先按照流(“flow”)对其进行分类,再在其所在的流中寻找相邻的数据包(“neighbor”)进行合并。若无法找到匹配的流,就插入一条新流并将数据包存储到新流中。若无法找到邻居,则将数据包存储到对应的流中。

基于Key的合包算法有两个特点。首先,通过流分类来加速数据包的合并是十分轻量的一种做法;其次,保存无法合并的数据包(如乱序包)使得之后对其进行合并成为可能,故减轻了包乱序对合包带来的影响。

图6. 基于Key的合包算法流程

例如,TCP/IPv4 GRO使用源和目的Ethernet地址、IP地址、TCP端口号以及TCP Acknowledge Number定义流,使用TCP Sequence Number和IP ID决定TCP/IPv4包是否为邻居。若两个TCP/IPv4的数据包能够合并,则它们必须属于同一个流,并且TCP序号和IP ID必须连续。

4

DPDK GSO的分片策略

  • 分片流程 如图7所示,将一个数据包分片有3个步骤。首先,将包的数据负载分成许多长度更小的部分;其次,为每一个数据负载部分添加包头(新形成的数据包称为GSO Segment);最后,为每个GSO segment更新包头(如TCP Sequence Number)。

图7. GSO分片流程

  • GSO Segment的结构 生成一个GSO Segment的最简单方法就是拷贝包头和数据负载部分。但频繁的数据拷贝会降低GSO性能,因此,DPDK GSO采用了一种基于零拷贝的数据结构——Two-part MBUF——来组织GSO Segment。如图8所示,一个Two-part MBUF由一个Direct MBUF和多个Indirect MBUF组成。Direct MBUF用来存储包头,Indirect MBUF则类似于指针,指向数据负载部分。利用Two-part MBUF,生成一个GSO Segment仅需拷贝长度较短的包头,而不需要拷贝较长的数据负载部分。

图8. Two-part MBUF的结构

GRO库和GSO库的状态

目前,GRO库还处于一个初期阶段,仅对使用最广泛的TCP/IPv4数据包提供了合包支持。GSO库则支持更丰富的包类型,包括TCP/IPv4、VxLAN和GRE。

作者简介

胡嘉瑜,毕业于中国科学技术大学,现为英特尔软件工程师,主要从事DPDK中GRO、GSO和虚拟化方向的研发。

本文分享自微信公众号 - Linux阅码场(LinuxDev)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 劫持Linux idle进程做点自己的计算任务

    前面谈过如何隐藏一个进程,我说过,隐藏procfs接口那无异于掩耳盗铃,正确的做法应该是将task_struct从任何链表中摘除,仅仅保留于run queue。

    Linux阅码场
  • 宋宝华:Linux文件读写(BIO)波澜壮阔的一生

    网上关于BIO和块设备读写流程的文章何止千万,但是能够让你彻底读懂读明白的文章实在难找,可以说是越读越糊涂!

    Linux阅码场
  • 实现一个基于XDP_eBPF的学习型网桥

    eBPF技术风靡当下,eBPF字节码正以星火燎原之势被HOOK在Linux内核中越来越多的位置,在这些HOOK点上,我们可以像编写普通应用程序一样编写内核的HO...

    Linux阅码场
  • 基于Spark Mllib的文本分类

    基于Spark Mllib的文本分类 文本分类是一个典型的机器学习问题,其主要目标是通过对已有语料库文本数据训练得到分类模型,进而对新文本进行类别标签的预测。这...

    Spark学习技巧
  • Java EE之SSM框架整合开发 -- (4) Spring AOP

    答:AOP(Aspect-Oriented Programming),即面向切面编程。

    浩Coding
  • 产品需求文档:C端生鲜电商APP

    (1)在居民生活品质意识加强及物流产业发展日渐成熟的推动下,中国冷链物流市场规模不断扩大,2019年冷链物流市场规模已达3780亿元,并预计在2020年达到48...

    物流IT圈
  • 低延迟分块流中的带宽预测

    本文整理自Mile High Video 2019上Ali.C.Begen的演讲。Ali目前是Ozyegin大学的计算机科学教授,也是Comcast视频架构,战...

    用户1324186
  • 网络带宽是什么

    最近有盆友在购买云服务器,问我带宽选多大的比较合适?当时我说,就你这小网站,整个1M妥妥的。

    烟草的香味
  • 腾讯云cvm公网IP带宽上限

    见文档 https://cloud.tencent.com/document/product/213/12523

    用户7316624
  • React Native发布APP之签名打包APK

    React Native发布APP之签名打包APK ---- 用React Native开发好APP之后,如何将APP发布以供用户使用呢?一款APP的发布流程...

    CrazyCodeBoy

扫码关注云+社区

领取腾讯云代金券