DPDK学习总结(一)简介

移动-懒猫 2018-12-19

linux 架构 性能 线程 多线程 CPU 协议栈 DPDK

开始学习DPDK,将学习中的心得和分析记录下来,以免时间久了自己都忘记了,也便于和其他同道中人交流。
说是学习心得和体会,但也借鉴了书籍和其他网友的分析总结,在学习他人总结过程中发现介绍往往浅尝辄止,知其然不知其所以然,因此本学习总结希望可以从一个初学者的角度来介绍,尽量做到知其然及知其所以然,可能大家会觉得别人一两句话说完的事情这里用了一个章节来描述很啰嗦,但与其看10个千篇一律的短文,不如看一个略有啰嗦但全面的长文。个人能力有限,有些内容直接取自书籍或者其他大牛的文章,如有介意请联系我删除相关章节,我也会根据学习的逐步深入,反回来修改、完善某些内容。

1 什么是DPDK
Intel® DPDK 全称 __Intel Data Plane Development Kit__,最初是intel提供的数据平面开发工具集,为Intel architecture(IA)处理器架构下用户空间高效的数据包处理提供库函数和驱动的支持,它不同于Linux系统以通用性设计为目的,而是专注于网络应用中数据包的高性能处理。其工作在用户层,取代传统Linux系统中的网络数据报文处理。但需要注意的是,DPDK提供的是高性能处理报文的能力,而不是对报文的处理。这也提供了我们自定义用户协议栈的能力。
传统上,网卡驱动程 序运行在Linux的内核态,以中断方式来唤醒系统处理,这和历史形成有关。早期CPU运行速度远高于外设访问,所以中断处理方式十分有 效,但随着芯片技术与高速网络接口技术的一日千里式发展,报文吞吐 需要高达10Gbit/s的端口处理能力,市面上已经出现大量的25Gbit/s、40Gbit/s甚至100Gbit/s高速端口,主流处理器的主频仍停留在3GHz以下。I/O超越CPU的运行速率,是横在行 业面前的技术挑战。用轮询来处理高速端口开始成为必然,这构成了 DPDK运行的基础。
在理论框架和核心技术取得一定突破后,Intel与6wind进行了合 作,交由在法国的软件公司进行部分软件开发和测试,6wind向Intel交 付了早期的DPDK软件开发包。2011年开始,6wind、Windriver、 Tieto、Radisys先后宣布了对Intel DPDK的商业服务支持。2013年4月,6wind联合其他开发者成立www.dpdk.org的开源社区,DPDK开始走上开源的大道。
在多架构支持方面,DPDK社区也取得了很大的进展,IBM中国研 究院的祝超博士启动了将DPDK移植到Power体系架构的工作,Freescale 的中国开发者也参与修改,Tilera与Ezchip的工程师也花了不少精力将 DPDK运行在Tile架构下。很快,DPDK从单一的基于Intel平台的软件, 逐步演变成一个相对完整的生态系统,覆盖了多个处理器、以太网和硬 件加速技术。所以,不要再认为DPDK只能在Intel architecture(IA)处理器架构下跑了。

2 DPDK的优势
要想知道优势,就要先了解之前技术的劣势,许多介绍DPDK的文章都会提到DPDK的优势,但许多都没有介绍实现原理,这里参考已有信息,对原理也做了描述:
以Linux为例,传统网络设备驱动包处理的动作可以概括如下:
•数据包到达网卡设备。
•网卡设备依据配置进行DMA操作。
•网卡发送中断,唤醒处理器。
•驱动软件填充读写缓冲区数据结构。
•数据报文达到内核协议栈,进行高层处理。
•如果最终应用在用户态,数据从内核搬移到用户态。
•如果最终应用在内核态,在内核继续进行。

期间存在问题如下:
 中断处理。当网络中大量数据包到来时,会产生频繁的硬件中断请求,这些硬件中断可以打断之前较低优先级的软中断或者系统调用的执行过程,如果这种打断频繁的话,将会产生较高的性能开销。

 内存拷贝。正常情况下,一个网络数据包从网卡到应用程序需要经过如下的过程:数据从网卡通过 DMA 等方式传到内核开辟的缓冲区,然后从内核空间拷贝到用户态空间,在 Linux 内核协议栈中,这个耗时操作甚至占到了数据包整个处理流程的 57.1%。

 上下文切换。频繁到达的硬件中断和软中断都可能随时抢占系统调用的运行,这会产生大量的上下文切换开销。另外,在基于多线程的服务器设计框架中,线程间的调度也会产生频繁的上下文切换开销,同样,锁竞争的耗能也是一个非常严重的问题。

 局部性失效。如今主流的处理器都是多个核心的,这意味着一个数据包的处理可能跨多个 CPU 核心,比如一个数据包可能中断在 cpu0,内核态处理在 cpu1,用户态处理在 cpu2,这样跨多个核心,容易造成 CPU 缓存失效,造成局部性失效。如果是 NUMA 架构,更会造成跨 NUMA 访问内存,性能受到很大影响。

 内存管理。传统服务器内存页为 4K,为了提高内存的访问速度,避免 cache miss,可以增加 cache 中映射表的条目,但这又会影响 CPU 的检索效率。

针对上述问题,DPDK的解决方式如下:

  • 轮询与中断:
    起初的纯轮询模式是指收发包完全不使用任何中断,集中所有运算资源用于报文处理。DPDK纯轮询模式是指收发包完全不使用中断处理的高吞吐率的方 式。DPDK所有的收发包有关的中断在物理端口初始化的时候都会关 闭,也就是说,CPU这边在任何时候都不会收到收包或者发包成功的中 断信号,也不需要任何收发包有关的中断处理。具体收发包流程参见之后的文章单独说明。网络应用中可能存在的潮汐效应,在某些时间段网络数据 流量可能很低,甚至完全没有需要处理的包,这样就会出现在高速端口 下低负荷运行的场景,而完全轮询的方式会让处理器一直全速运行,明 显浪费处理能力和不节能。因此在DPDK R2.1和R2.2陆续添加了收包中 断与轮询的混合模式的支持,类似NAPI的思路,用户可以根据实际应 用场景来选择完全轮询模式,或者混合中断轮询模式。而且,完全由用 户来制定中断和轮询的切换策略,比如什么时候开始进入中断休眠等待 收包,中断唤醒后轮询多长时间,等等。
  • 多核多线程编程:
    多线程编程早已不是什么新鲜的事物了,多线程的初衷是提高整体应用程序的性能,但是如果不加注意,就会将多线程的创建和销毁开销,锁竞争,访存冲突,cache失效,上下文切换等诸多消耗性能的因素引入进来。为了进一步提高性能,就必须仔细斟酌考虑线程在CPU不同核上的分布情况,这也就是常说的多核编程。多核编程和多线程有很大的不同:多线程是指每个CPU上可以运行多个线程,涉及到线程调度、锁机制以及上下文的切换;而多核则是每个CPU核一个线程,核心之间访问数据无需上锁。为了最大限度减少线程调度的资源消耗,需要将Linux绑定在特定的核上,释放其余核心来专供应用程序使用。DPDK的线程基于pthread接口创建,属于抢占式线程模型,受内核 调度支配。DPDK通过在多核设备上创建多个线程,每个线程绑定到单 独的核上,减少线程调度的开销,以提高性能。DPDK的线程可以作为控制线程,也可以作为数据线程。在DPDK 的一些示例中,控制线程一般绑定到MASTER核上,接受用户配置,并 传递配置参数给数据线程等;数据线程分布在不同核上处理数据包。同时还需要考虑CPU特性和系统是否支持NUMA架构,如果支持的话,不同插槽上CPU的进程要避免访问远端内存,尽量访问本端内存。
  • CPU亲和性:
    当处理器进入多核架构后,自然会面对一个问题,按照什么策略将 任务线程分配到各个处理器上执行。众所周知的是,这个分配工作一般 由操作系统完成。负载均衡当然是比较理想的策略,按需指定的方式也 是很自然的诉求,因为其具有确定性。简单地说,CPU亲和性(Core affinity)就是一个特定的任务要在某 个给定的CPU上尽量长时间地运行而不被迁移到其他处理器上的倾向 性。这意味着线程可以不在处理器之间频繁迁移。这种状态正是我们所 希望的,因为线程迁移的频率小就意味着产生的负载小。将线程与CPU绑定,最直观的好处就是提高了CPU Cache的命中 率,从而减少内存访问损耗,提高程序的速度。在Linux内核中,所有的线程都有一个相关的数据结构,称为 task_struct。这个结构非常重要,原因有很多;其中与亲和性相关度最 高的是cpus_allowed位掩码。这个位掩码由n位组成,与系统中的n个逻 辑处理器一一对应。具有4个物理CPU的系统可以有4位。如果这些CPU 都启用了超线程,那么这个系统就有一个8位的位掩码。如果针对某个线程设置了指定的位,那么这个线程就可以在相关的 CPU上运行。因此,如果一个线程可以在任何CPU上运行,并且能够根 据需要在处理器之间进行迁移,那么位掩码就全是1。实际上,在Linux 中,这就是线程的默认状态。DPDK通过把线程绑定到逻辑核的方法来避免跨核任务中的切换开 销,但对于绑定运行的当前逻辑核,仍然可能会有线程切换的发生,若 希望进一步减少其他任务对于某个特定任务的影响,在亲和的基础上更 进一步,可以采取把逻辑核从内核调度系统剥离的方法。
  • 大页表:
    默认下Linux采用4KB为一页,页越小内存越大,页表的开销越大,页表的内存占用也越大。CPU有TLB(Translation Lookaside Buffer)成本高所以一般就只能存放几百到上千个页表项。如果进程要使用64G内存,则64G/4KB=16000000(一千六百万)页,每页在页表项中占用16000000 * 4B=62MB。如果用HugePage采用2MB作为一页,只需64G/2MB=2000,数量不在同个级别。而DPDK采用HugePage,在x86-64下支持2MB、1GB的页大小,几何级的降低了页表项的大小,从而减少TLB-Miss。
  • 无锁机制:
    实际上DPDK内部也有读写锁,LINUX系统本身也支持无锁操作,并且DPDK内部的无锁机制实现原理同LINUX系统提供的无锁机制的实现原理类似。两者都采用无锁环形队列的方式,采用环形队列的好处是,当一个数据元素被用掉后,其余数据元素不需要移动其存储位置,从而减少拷贝,提高效率。LINUX系统如果仅仅有一个读用户和一个写用户,那么不需要添加互斥保护机制就可以 保证数据的正确性。但是,如果有多个读写用户访问环形缓冲区,那么 必须添加互斥保护机制来确保多个用户互斥访问环形缓冲区。DPDK的无锁环形队列无论是单用户读写还是多用户读写都不需要使用互斥锁保护。
  • cache预取
    处理器从一级Cache读取数据需要3~5个时 钟周期,二级是十几个时钟周期,三级是几十个时钟周期,而内存则需 要几百个时钟周期。DPDK必须保证所有需要读取的数据都在Cache中,否则一旦出现Cache不命中,性能将会严重下降。为了保证这点,DPDK采用 了多种技术来进行优化,预取只是其中的一种。
  • 利用UIO支持
    为了让驱动运行在用户态,Linux提供UIO机制。使用UIO可以通过read感知中断,通过mmap实现和网卡的通讯。

image

要开发用户态驱动有几个步骤:
1.开发运行在内核的UIO模块,因为硬中断只能在内核处理
2.通过/dev/uioX读取中断
3.通过mmap和外设共享内存

  • 其他:
    在网上看到DPDK还做了其他优化,包括SNA(Shared-nothing Architecture)、SIMD(Single Instruction Multiple Data)、不使用慢速API、编译执行优化、内存对其、常量优化、使用CPU指令等。

3 DPDK陷阱
所谓无利不起早,intel耗费人力、物力、财力开发出DPDK给大家使用也不是良心泛滥,结合当前虚拟化浪潮汹涌,百花齐放,也带来了无尽的商机。
利用DPDK的 高速报文吞吐优势,对接运行在Linux用户态的程序,对成本降低和硬 件通用化有很大的好处,使得以软件为主体的网络设备成为可能。对 Intel® x86通用处理器而言,这是一个巨大的市场机会。
对于通信设备厂商,通用平台和软件驱动的开发方式具有易采购、 易升级、稳定性、节约成本的优点。

  • 易采购:通用服务器作为主流的基础硬件,拥有丰富的采购渠道 和供应商,供货量巨大。
  • 易升级:软件开发模式简单,工具丰富,最大程度上避免系统升 级中对硬件的依赖和更新,实现低成本的及时升级。
  • 稳定性:通用服务器平台已经通过大量功能的验证,产品稳定性 毋庸置疑。而且,对于专用的设计平台,系统稳定需要时间累积和大量 测试,尤其是当采用新一代平台设计时可能需要硬件更新,这就会带来 稳定性的风险。
  • 节约研发成本和降低复杂性:传统的网络设备因为功能复杂和高 可靠性需求,系统切分为多个子系统,每个子系统需要单独设计和选 型,独立开发,甚至选用单独的芯片。这样的系统需要构建复杂的开发 团队、完善的系统规划、有效的项目管理和组织协调,来确保系统开发 进度。而且,由于开发的范围大,各项目之间会产生路径依赖。而基于 通用服务器搭建的网络设备可以很好地避免这些问题。
登录 后评论
下一篇
corcosa
17005人浏览
2019-10-08
相关推荐
Intel DPDK 全面解读
1827人浏览
2018-02-02 13:01:00
京东商城ContainerLB实践
1230人浏览
2017-10-11 14:19:00
vhost-user 简介
4194人浏览
2018-02-06 12:37:00
0
0
0
3099