写点什么

DPDK 网络协议栈 -vpp-OvS-DDos- 虚拟化专家之路

作者:赖猫
  • 2021 年 11 月 24 日
  • 本文字数:2554 字

    阅读完需:约 8 分钟

DPDK 介绍

Intel® DPDK 全称 __Intel Data Plane Development Kit__,是 intel 提供的数据平面开发工具集,为 Intel architecture(IA)处理器架构下用户空间高效的数据包处理提供库函数和驱动的支持,它不同于 Linux 系统 以通用性设计为目的,而是专注于网络应用中数据包的高性能处理。其工作在用户层,取代传统 Linux 系统 中的网络数据报文处理。但需要注意的是,DPDK 提供的是高性能处理报文的能力,而不是对报文的处理。这也提供了我们自定义用户协议栈的能力

DPDK 的优势

1、轮询与中断

起初的纯轮询模式是指收发包完全不使用任何中断,集中所有运算资源用于报文处理。DPDK 纯轮询模式 是指收发包完全不使用中断处理的高吞吐率的方 式。DPDK 所有的收发包有关的中断在物理端口初始化的时候都会关 闭,也就是说,CPU 这边在任何时候都不会收到收包或者发包成功的中 断信号,也不需要任何收发包有关的中断处理。具体收发包流程参见之后的文章单独说明。网络应用中可能存在的潮汐效应,在某些时间段网络数据 流量可能很低,甚至完全没有需要处理的包,这样就会出现在高速端口 下低负荷运行的场景,而完全轮询的方式会让处理器一直全速运行,明 显浪费处理能力和不节能。因此在 DPDK R2.1 和 R2.2 陆续添加了收包中 断与轮询的混合模式的支持,类似 NAPI 的思路,用户可以根据实际应 用场景来选择完全轮询模式,或者混合中断轮询模式。而且,完全由用 户来制定中断和轮询的切换策略,比如什么时候开始进入中断休眠等待 收包,中断唤醒后轮询多长时间,等等。

2、多线程编程:

多线程编程早已不是什么新鲜的事物了,多线程的初衷是提高整体应用程序的性能,但是如果不加注意,就会将多线程的创建和销毁开销,锁竞争,访存冲突,cache 失效,上下文切换等诸多消耗性能的因素引入进来。为了进一步提高性能,就必须仔细斟酌考虑线程在 CPU 不同核上的分布情况,这也就是常说的多核编程。多核编程和多线程有很大的不同:多线程是指每个 CPU 上可以运行多个线程,涉及到线程调度、锁机制以及上下文的切换;而多核则是每个 CPU 核一个线程,核心之间访问数据无需上锁。为了最大限度减少线程调度的资源消耗,需要将 Linux 绑定在特定的核上,释放其余核心来专供应用程序使用。DPDK 的线程基于 pthread 接口创建,属于抢占式线程模型,受内核 调度支配。DPDK 通过在多核设备上创建多个线程,每个线程绑定到单 独的核上,减少线程调度的开销,以提高性能。DPDK 的线程可以作为控制线程,也可以作为数据线程。在 DPDK 的一些示例中,控制线程一般绑定到 MASTER 核上,接受用户配置,并 传递配置参数给数据线程等;数据线程分布在不同核上处理数据包。同时还需要考虑 CPU 特性和系统是否支持 NUMA 架构,如果支持的话,不同插槽上 CPU 的进程要避免访问远端内存,尽量访问本端内存。

3、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 通过把线程绑定到逻辑核的方法来避免跨核任务中的切换开 销,但对于绑定运行的当前逻辑核,仍然可能会有线程切换的发生,若希望进一步减少其他任务对于某个特定任务的影响,在亲和的基础上更 进一步,可以采取把逻辑核从内核调度系统剥离的方法。

4、大页表:

默认下 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 。

5、无锁机制:

实际上 DPDK 内部也有读写锁,LINUX 系统本身也支持无锁操作,并且 DPDK 内部的无锁机制实现原理同 LINUX 系统提供的无锁机制的实现原理类似。两者都采用无锁环形队列的方式,采用环形队列的好处是,当一个数据元素被用掉后,其余数据元素不需要移动其存储位置,从而减少拷贝,提高效率。LINUX 系统如果仅仅有一个读用户和一个写用户,那么不需要添加互斥保护机制就可以 保证数据的正确性。但是,如果有多个读写用户访问环形缓冲区,那么 必须添加互斥保护机制来确保多个用户互斥访问环形缓冲区。DPDK 的无锁环形队列无论是单用户读写还是多用户读写都不需要使用互斥锁保护。

6、cache 预取:

处理器从一级 Cache 读取数据需要 3~5 个时 钟周期,二级是十几个时钟周期,三级是几十个时钟周期,而内存则需 要几百个时钟周期。DPDK 必须保证所有需要读取的数据都在 Cache 中,否则一旦出现 Cache 不命中,性能将会严重下降。为了保证这点,DPDK 采用 了多种技术来进行优化,预取只是其中的一种

7、利用 UIO 技术:

为了让驱动运行在用户态,Linux 提供 UIO 机制。使用 UIO 可以通过 read 感知中断,通过 mmap 实现和网卡的通讯


DPDK 学习路线

DPDK 网络







DPDK/网络协议栈 学习教程有需要的可以自行添加学习交流群960994558

用户头像

赖猫

关注

C/C++Linux服务器开发学习群960994558 2020.11.28 加入

纸上得来终觉浅,绝知此事要躬行

评论

发布
暂无评论
DPDK 网络协议栈-vpp-OvS-DDos-虚拟化专家之路