手把手实现tcp/ip用户态协议栈,帮你实践网络知识(网络必备,面试项目)

简介: 手把手实现tcp/ip用户态协议栈,帮你实践网络知识(网络必备,面试项目)

一、DPDK简介

DPDK(Data Plane Development Kit)是一个开源的数据平面开发工具包,它提供了一组C语言库和驱动程序,用于快速开发高性能的数据平面应用程序。DPDK使用用户空间的方式来实现网络数据包处理,从而避免了传统内核态和用户态之间频繁切换导致的性能损失。


DPDK支持多种硬件平台和操作系统,并且在各种场景下都表现出优异的性能。例如,在云计算、电信、金融、在线游戏等行业中,DPDK被广泛应用于高速网络数据处理、虚拟化网络功能和SDN等方面。


二、DPDK的主要目的


DPDK的主要目的是提供一种快速、高效、灵活的数据平面开发框架,帮助开发人员轻松构建高性能的网络应用程序。


具体来说,DPDK致力于解决以下问题:


1. 提高数据包处理性能:通过使用用户空间和优化算法等技术手段,DPDK显著提升了数据包处理性能,可以达到数百万pps(每秒数据包数)的级别。


2. 支持多种硬件平台和操作系统:DPDK支持多种常见硬件平台和操作系统,并且可以与其他开源项目(如Open vSwitch、OpenStack等)集成使用。


3. 提供易用的API:DPDK提供了一组易用的C语言API,使得开发人员可以轻松地编写高性能的网络应用程序。


4. 支持各种场景下的应用:由于其高性能和灵活性,DPDK被广泛应用于云计算、电信、金融、在线游戏等行业中,涉及到高速网络数据处理、虚拟化网络功能和SDN等方面。


三、工作环境


DPDK的环境抽象层向应用与函数库隐藏了底层环境的细节,因而能扩展到任何处理器上使用。就操作系统来说,它提供了对Linux和FreeBSD的支持。


还不熟悉的朋友,这里可以先领取一份dpdk新手学习资料包(入坑不亏):

1699516667360.png

就市场而言,随着业务量用户量的增长,会有越来越多的公司用到dpdk,而学好dpdk也会成为你进军优秀的互联网公司甚至大厂的一个方向。关于dpdk的学习他不同与java偏业务,更多的是重视你对底层技术的理解,对计算机原理基础的学习程度以及你的学历。


一句话形容:与业务关联不大,与底层技术关系较大

四、工作原理


DPDK使用了轮询(polling)而不是中断来处理数据包。在收到数据包时,经DPDK重载的网卡驱动不会通过中

断通知CPU,而是直接将数据包存入内存,交付应用层软件通过DPDK提供的接口来直接处理,这样节省了大量的CPU中断时间和内存拷贝时间。


DPDK工作原理:


初始化:在应用程序启动时,DPDK初始化了所有需要的硬件设备、线程和内存池等资源,并且为每个CPU核心分配一个独立的运行环境。

接收数据:当一个数据包到达网卡时,DPDK会将其缓存在一个环形缓冲区中,并通知应用程序有新数据到达。

数据包分类:应用程序根据预定义的规则对数据包进行分类(例如流量监控、负载均衡、安全检查等),并将它们发送到相应的队列中。

数据包处理:DPDK从队列中取出待处理的数据包,并使用用户空间驱动程序(userspace driver)进行数据包解析、协议转换和业务逻辑处理等操作。

数据包发送:完成处理后,DPDK将结果重新打包成网络报文,并通过网卡发送回网络中。

回收资源:当应用程序不再需要某些资源时,DPDK会将它们释放回内存池或者硬件设备中,以便其他线程或者进程使用。


4.1技术原理与架构


由于采用软件转发和软件交换技术,单服务器内部的转发能力是 NFV 系统的主要性能瓶颈。在各类高速转发的 NFV 应用中,数据报文从网卡中接收,再传送到虚拟化的用户态应用程序(VNF)处理,整个过程要经历 CPU 中断处理、虚拟化 I/O 与地址映射转换、虚拟交换层、网络协议栈、内核上下文切换、内存拷贝等多个费时的 CPU 操作和 I/O 处理环节。


业内通常采用消除海量中断、旁路内核协议栈、减少内存拷贝、CPU 多核任务分担、Intel VT 等技术来综合提升服务器数据平面的报文处理性能,普通用户较难掌握。业界迫切需要一种综合的性能优化方案,同时提供良好的用户开发和商业集成环境,DPDK 加速技术方案成为其中的典型代表。


DPDK 是一个开源的数据平面开发工具集,提供了一个用户空间下的高效数据包处理库函数,它通过环境抽象层旁路内核协议栈、轮询模式的报文无中断收发、优化内存/缓冲区/ 队列管理、基于网卡多队列和流识别的负载均衡等多项技术,实现了在 x86 处理器架构下的高性能报文转发能力,用户可以在 Linux 用户态空间开发各类高速转发应用,也适合与各类商业化的数据平面加速解决方案进行集成。


英特尔在 2010 年启动了对 DPDK 技术的开源化进程,于当年 9 月通过 BSD 开源许可协议正式发布源代码软件包,为开发者提供支持。开源社区的参与者们大幅推进了 DPDK 的技术创新和快速演进, 而今它已发展成为 SDN 和 NFV 的一项关键技术。


4.2主要特点


基于 OS 内核的数据传输有什么弊端


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

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

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

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

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


针对这些问题,可探讨的技术点


控制层和数据层分离。将数据包处理、内存管理、处理器调度等任务转移到用户空间去完成,而内核仅仅负责部分控制指令的处理。这样就不存在上述所说的系统中断、上下文切换、系统调用、系统调度等等问题。

使用多核编程技术代替多线程技术,并设置 CPU 的亲和性,将线程和 CPU 核进行一比一绑定,减少彼此之间调度切换。

针对 NUMA 系统,尽量使 CPU 核使用所在 NUMA 节点的内存,避免跨内存访问。

使用大页内存代替普通的内存,减少 cache-miss。

采用无锁技术解决资源竞争问题。


DPDK 的组成架构如下图所示,相关技术原理概述如下:


图中,在最底部的内核态(Linux Kernel)DPDK 有两个模块:KNI 与 IGB_UIO。其中,KNI 提供给用户一个使用 Linux 内核态的协议栈,以及传统的Linux 网络工具(如ethtool, ifconfig)。IGB_UIO(igb_uio.ko 和 kni.ko. IGB_UIO)则借助了 UIO 技术,在初始化过程中将网卡硬件寄存器映射到用户态。


如图所示,DPDK 的上层用户态由很多库组成,主要包括核心部件库(Core Libraries)、平台相关模块(Platform)、网卡轮询模式驱动模块(PMD-Natives&Virtual)、QoS 库、报文转发分类算法(Classify)等几大类,用户应用程序可以使用这些库进行二次开发,下面分别简要介绍。


UIO(Linux Userspace I/O) 提供应用空间下驱动程序的支持,也就是说网卡驱动是运行在用户空间的,减下了报文在用户空间和应用空间的多次拷贝。如图:DPDK绕过了Linux内核的网络驱动模块,直接从网络硬件到达用户空间,不需要进行频繁的内存拷贝和系统调用。根据官方给出的数据,DPDK裸包反弹每个包需要80个时钟周期,而传统Linux内核协议栈每包需要2k~4k个时钟周期。DPDK能显著提升虚拟化网络设备的数据采集效率。


不使用与使用DPDK的Linux内核对比


UIO技术的工作原理:



UIO技术将设备驱动分为用户空间驱动和内核空间驱动两部分,内核空间驱动主要负责设备资源分配、UIO设备注册以及小部分中断响应函数,驱动的大部分工作在用户空间的驱动程序下完成。通过UIO框架提供的API接口将UIO的驱动注册到内核,注册完成后将生成存有设备物理地址等信息的map文件,用户态进程访问该文件将设备对应的内存空间地址映射到用户空间,即可直接操作设备的内存空间,UIO技术使得应用程序可以通过用户空间驱动直接操作设备的内存空间,避免了数据在内核缓冲区和应用程序缓冲区的多次拷贝,提供数据处理效率。


简单地说,DPDK使高速数据包网络应用程序的开发变得更快,这意味着它允许构建能够更快地处理数据包的应用程序,这多亏了内核的绕过。实际上,它使用了快速路径,而不是正常的网络层路径和上下文切换路径。包被直接传递到用户空间(作为原始包)。如下图为linux内核包处理和dpdk包处理的区别。


linux内核处理包


dpdk处理包


slow路径和fast路径比较


核心部件库


该模块构成的运行环境是建立在 Linux 上,通过环境抽象层(EAL)的运行环境进行初始化,包括:HugePage 内存分配、内存/缓冲区/队列分配与无锁操作、CPU 亲和性绑定等;其次,EAL 实现了对操作系统内核与底层网卡 I/O 操作的屏蔽(I/O 旁路了内核及其协议栈),为 DPDK 应用程序提供了一组调用接口,通过 UIO 或 VFIO 技术将 PCI 设备地址映射到用户空间,方便了应用程序调用,避免了网络协议栈和内核切换造成的处理延迟。另外,核心部件还包括创建适合报文处理的内存池、缓冲区分配管理、内存拷贝、以及定时器、环形缓冲区管理等。


DPDK主要有六个核心组件:


  • 1、 环境抽象层(EAL)为DPDK其他组件和应用程序提供一个屏蔽具体平台特性的统一接口,环境抽象层提供的功能主要有:DPDK加载和启动;支持多核和多线程执行类型;CPU核亲和性处理;原子操作和锁操作接口;时钟参考;PCI总线访问接口;跟踪和调试接口;CPU特性采集接口;中断和告警接口等。
  • 2、 堆内存管理组件(Malloc lib)堆内存管理组件为应用程序提供从大页内存分配对内存的接口。当需要分配大量内存小块时,使用这些接口可以减少TLB缺页。
  • 3、 环缓冲区管理组件(Ring lib)环缓冲区管理组件为应用程序和其他组件提供一个无锁的多生产者多消费者FIFO队列API:Ring。Ring是借鉴了Linux内核kfifo无锁队列,可以无锁出入对,支持多消费/生产者同时出入队。
  • 4、 内存池管理组件(Mem pool lib)为应用程序和其他组件提供分配内存池的接口,内存池是一个由固定大小的多个内存块组成的内存容器,可用于存储相同对象实体,如报文缓存块等。内存池由内存池的名称来唯一标识,它由一个环缓冲区和一组核本地缓存队列组成,每个核从自己的缓存队列分配内存块,当本地缓存队列减少到一定程度时,从内存缓冲区中申请内存块来补充本地队列。
  • 5、网络报文缓存块管理组件(Mbuf lib)提供应用程序创建和释放用于存储报文信息的缓存块的接口,这些MBUF存储在内存池中。提供两种类型的MBUF,一种用于存储一般信息,一种用于存储报文信息。
  • 6、 定时器组件(Timer lib)提供一些异步周期执行的接口(也可以只执行一次),可以指定某个函数在规定的时间异步的执行,就像LIBC中的timer定时器,但是这里的定时器需要应用程序在主循环中周期调用rte_timer_manage来使定时器得到执行。定时器组件的时间参考来自EAL层提供的时间接口。


除了以上六个核心组件外,DPDK还提供以下功能:


  • 1) 以太网轮询模式驱动(PMD)架构:把以太网驱动从内核移到应用层,采用同步轮询机制而不是内核态的异步中断机制来提高报文的接收和发送效率。
  • 2)报文转发算法支持:Hash 库和LPM库为报文转发算法提供支持。
  • 3) 网络协议定义和相关宏定义:基于FreeBSD IP协议栈的相关定义如:TCP、UDP、SCTP等协议头定义。
  • 4)报文QOS调度库:支持随机早检测、流量整形、严格优先级和加权随机循环优先级调度等相关QOS 功能。
  • 5)内核网络接口库(KNI):提供一种DPDK应用程序与内核协议栈的通信的方法、类似普通Linux的TUN/TAP接口,但比TUN/TAP接口效率高。每个物理网口可以虚拟出多个KNI接口。



平台相关模块


其内部模块主要包括 KNI、能耗管理以及 IVSHMEM 接口。其中,KNI 模块主要通过 kni.ko 模块将数据报文从用户态传递给内核态协议栈处理,以便用户进程使用传统的 socket 接口对相关报文进行处理;能耗管理则提供了一些API,应用程序可以根据收包速率动态调整处理器频率或进入处理器的不同休眠状态;另外,IVSHMEM 模块提供了虚拟机与虚拟机之间,或者虚拟机与主机之间的零拷贝共享内存机制,当 DPDK 程序运行时,IVSHMEM 模块会调用核心部件库 API,把几个 HugePage 映射为一个 IVSHMEM 设备池,并通过参数传递给 QEMU,这样,就实现了虚拟机之间的零拷贝内存共享。


用户空间轮询模式(PMD)


传统中断模式:传统Linux系统中,当网络设备检测到数据帧过来的时候,会使用DMA(直接内存访问)将帧发送到预先分配好的内核缓冲区里面,然后更新相应的接收描述符环,之后产生中断通知有数据帧过来。Linux系统会进行相应的响应,然后更新相应的描述符环,再将接收到的数据帧交给内核中的网络堆栈进行处理,网络堆栈处理完之后会将相应的数据拷贝到相应的套接字,从而数据就被复制到了用户空间,应用程序就可以使用这些数据了,数据帧的接收过程如图:



数据帧的接收过程


在发送的时候,一旦用户程序处理完了数据,会通过一个系统调用将数据写入到套接字,将数据从用户空间拷贝到内核空间的缓冲区,交由网络堆栈进行处理,网络堆栈根据需要对数据进行封装并调用网卡设备的驱动程序,网卡设备驱动程序会更新传输描述符环,然后向网卡设备告知有数据帧需要传输。网卡设备会将数据帧从内核中的缓冲区拷贝到自己的缓冲区中并发送到网络链路上,传送到链路上之后,网卡设备会通过一个中断告知成功发送,然后内核会释放相应的缓冲区。


数据的发送如图:


数据帧的发送过程


由于linux系统是通过中断的方式告知CPU有数据包过来的,当网络的流量越来越大,linux系统会浪费越来越多的时间去处理中断,当流量速率达到10G的时候,linux系统可能会被中断淹没,浪费很多CPU资源。


DPDK用户空间的轮询模式驱动:用户空间驱动使得应用程序不需要经过linux内核就可以访问网络设备卡。网卡设备可以通过DMA方式将数据包传输到事先分配好的缓冲区,这个缓冲区位于用户空间,应用程序通过不断轮询的方式可以读取数据包并在原地址上直接处理,不需要中断,而且也省去了内核到应用层的数据包拷贝过程。


因此相对于linux系统传统中断方式,Intel DPDK避免了中断处理、上下文切换、系统调用、数据复制带来的性能上的消耗,大大提升了数据包的处理性能。同时由于Intel DPDK在用户空间就可以开发驱动,与传统的在内核中开发驱动相比,安全系数大大降低。因为内核层权限比较高,操作相对比较危险,可能因为小的代码bug就会导致系统崩溃,需要仔细的开发和广泛的测试。而在应用层则相反,比较安全,且在应用层调试代码要方便的多。


轮询模式驱动模块


PMD 相关 API 实现了在轮询方式下进行网卡报文收发,避免了常规报文处理方法中因采用中断方式造成的响应延迟,极大提升了网卡收发性能。此外,该模块还同时支持物理和虚拟化两种网络接口,从仅仅支持 Intel 网卡,发展到支持 Cisco、Broadcom、Mellanox、Chelsio 等整个行业生态系统,以及基于 KVM、VMWARE、 XEN 等虚拟化网络接口的支持。


DPDK 还定义了大量 API 来抽象数据平面的转发应用,如 ACL、QoS、流分类和负载均衡等。并且,除以太网接口外,DPDK 还在定义用于加解密的软硬件加速接口(Extensions)。


大页技术


处理器的内存管理包含两个概念:物理内存和虚拟内存。Linux 操作系统里面整个物理内存按帧(frames)来进行管理,虚拟内存按照页(page)来进行管理。


内存管理单元(MMU)完成从虚拟内存地址到物理内存地址的转换。内存管理单元进行地址转换需要的信息保存在一个叫页表(page table)的数据结构里面,页表查找是一种极其耗时的操作。为了减少页表的查找过程,Intel 处理器实现了一块缓存来保存查找结果,这块缓存被称为 TLB(Translation Lookaside Buffer),它保存了虚拟地址到物理地址的映射关系。所有虚拟地址在转换为物理地址以前,处理器会首先在 TLB 中查找是否已经存在有效的映射关系,如果没有发现有效的映射,也就是 TLS miss,处理器再进行页表的查找。页表的查找过程对性能影响极大,因此需要尽量减少 TLB miss 的发生。x86 处理器硬件在缺省配置下,页的大小是 4K,但也可以支持更大的页表尺寸,例如2M 或 1G 的页表。使用了大页表功能后,一个 TLB 表项可以指向更大的内存区域,这样可以大幅减少 TLB miss 的发生。早期的 Linux 并没有利用x86 硬件提供的大页表功能,仅在 Linux 内核 2.6.33 以后的版本,应用软件才可以使用大页表功能,具体的介绍可以参见 Linux 的大页表文件系统(hugetlbfs)特性。


DPDK 则利用大页技术,所有的内存都是从 HugePage 里分配,实现对内存池(mempool) 的管理,并预先分配好同样大小的 mbuf,供每一个数据包使用。


DPDK中的内存管理如图,最下面是连续的物理内存,这些物理内存是由2MB的大页组成,连续的物理内存上面是内存段,内存段之上则是内存区,我们分配的基本单元对象是在内存区中分配的,内存区包含了ring队列,内存池、LPM路由表还有其他一些高性能的关键结构。



轮询技术


传统网卡的报文接收/发送过程中,网卡硬件收到网络报文,或发送完网络报文后,需要发送中断到 CPU,通知应用软件有网络报文需要处理。在 x86 处理器上,一次中断处理需要将处理器的状态寄存器保存到堆栈,并运行中断服务程序,最后再将保存的状态寄存器信息从堆栈中恢复。整个过程需要至少 300 个处理器时钟周期。对于高性能网络处理应用,频繁的中断处理开销极大降低了网络应用程序的性能。


为了减少中断处理开销,DPDK 使用了轮询技术来处理网络报文。网卡收到报文后,直接将报文保存到处理器 cache 中(有 DDIO(Direct Data I/O)技术的情况下),或者保存到内存中(没有 DDIO 技术的情况下),并设置报文到达的标志位。应用软件则周期性地轮询报文到达的标志位,检测是否有新报文需要处理。整个过程中完全没有中断处理过程,因此应用程序的网络报文处理能力得以极大提升。


CPU亲和技术


现代操作系统都是基于分时调用方式来实现任务调度,多个进程或线程在多核处理器的某一个核上不断地交替执行。每次切换过程,都需要将处理器的状态寄存器保存在堆栈中, 并恢复当前进程的状态信息,这对系统其实是一种处理开销。将一个线程固定一个核上运行, 可以消除切换带来的额外开销。另外将进程或者线程迁移到多核处理器的其它核上进行运行时,处理器缓存中的数据也需要进行清除,导致处理器缓存的利用效果降低。


CPU 亲和技术,就是将某个进程或者线程绑定到特定的一个或者多个核上执行,而不被迁移到其它核上运行,这样就保证了专用程序的性能。


DPDK 使用了 Linux pthread 库,在系统中把相应的线程和 CPU 进行亲和性绑定, 然后相应的线程尽可能使用独立的资源进行相关的数据处理。


在一个多核处理器的机器上,每个CPU核心本身都存在自己的缓存,缓冲区里存放着线程使用的信息。如果线程没有绑定CPU核,那么线程可能被Linux系统调度到其他的CPU上,这样的话,CPU的cache命中率就降低了。利用CPU的affinity技术,一旦线程绑定到某个CPU后,线程就会一直在指定的CPU上运行,操作系统不会将其调度到其他的CPU上,节省了调度的性能消耗,从而提升了程序执行的效率。


多核轮询模式:多核轮询模式有两种,分别是IO独占式和流水线式。IO独占式是指每个核独立完成数据包的接收、处理和发送过程,核之间相互独立,其优点是其中一个核出现问题时不影响其他核的数据收发。流水线式则采用多核合作的方式处理数据包,数据包的接收、处理和发送由不同的核完成。流水线式适合面向流的数据处理,其优点是可对数据包按照接收的顺序有序进行处理,缺点是当某个环境(例如接收)所涉及的核出现阻塞,则会造成收发中断。


IO独占式多核轮询模式中每个网卡只分配给一个逻辑核进行处理。每个逻辑核给所接管的网卡分别分配一个发送队列和一个接收队列,并且独立完成数据包的接收、处理和发送的过程,核与核之间相互独立。系统数据包的处理由多个逻辑核同时进行,每个网卡的收发包队列只能由一个逻辑核提供。当数据包进入网卡的硬件缓存区,用户空间提供的网卡驱动通过轮询得知网卡收到数据包,从硬件缓冲区中取出数据包,并将数据包存入逻辑核提供的收包队列中,逻辑核取出收包队列中的数据包进行处理,处理完毕后将数据包存入逻辑核提供的发包队列,然后由网卡驱动取出发往网卡,最终发送到网络中。



DPDK在AWCloud中的应用


DPDK(Data Plane Development Kit)数据平面开发工具集,为Intel architecture(IA)处理器架构下用户空间高效的数据包处理提供库函数和驱动的支持,它不同于Linux系统以通用性设计为目的,而是专注于网络应用中数据包的高性能处理。DPDK应用程序是运行在用户空间上利用自身提供的数据平面库来收发数据包,绕过了Linux内核协议栈对数据包处理过程。加速数据的处理,用户可以在用户空间定制协议栈,满足自己的应用需求。相对传统的基于内核的网络数据处理,DPDK对从内核层到用户层的网络数据流程进行了重大突破。


DPDK功能用于加速云主机和物理主机处理网络数据包的速度。配合大页内存和CPU Affinity等一系列技术,绕过系统对网络数据包处理的繁琐过程,提升网络性能。


云平台采用DPDK技术满足网络性能优化,如下图所示



内存池和无锁环形缓存管理

此外Intel DPDK将库和API优化成了无锁,比如无锁队列,可以防止多线程程序发生死锁。然后对缓冲区等数据结构进行了cache对齐。如果没有cache对齐,则可能在内存访问的时候多读写一次内存和cache。


内存池缓存区的申请和释放采用的是生产者-消费者模式无锁缓存队列进行管理,避免队列中锁的开销,在缓存区的使用过程中提高了缓冲区申请释放的效率。


无锁环形队列生产过程


无锁环形队列消费过程



如图所示,生产者往队列里存放内容的方向和消费者从队列里取内容的方向一致,均以顺时针方向进行。当缓存区向内存池申请内存块,或者应用程序进行内存块的释放时,缓存区的无锁环形队列的生产者指针顺时针移动,往队列中存入内存块地址信息,进行缓存队列的生产过程。当应用程序需要向缓冲区申请内存块使用时,缓冲区的无锁环形队列的消费者指针以顺时针的方向取出队列的内存块地址,分配给应用程序使用,该过程为缓存队列的消费过程。


生产n个对象过程:首先生产者头指针往顺时针方向移n个位置获得新的头指针,然后从生产者尾指针指的区域开始逐个存入n个对象,最后生产者尾指针顺时针移动n个位置获得新的生产者尾指针


消费n个对象过程:首先消费者头指针顺时针移动n个位置获得新的消费者头指针,然后从消费者尾指针处开始逐个读取n个对象,最后消费者尾指针顺时针移动n个位置获得新的消费者尾指针。


网络存储优化


4.3DPDK的突破


传统Linux内核网络数据流程


硬件中断--->取包分发至内核线程--->软件中断--->内核线程在协议栈中处理包--->处理完毕通知用户层
用户层收包-->网络层--->逻辑层--->业务层


dpdk 网络数据流程:

硬件中断--->放弃中断流程
用户层通过设备映射取包--->进入用户层协议栈--->逻辑层--->业务层


4.4KNI组件


KNI是DPDK平台提供的用于将数据重入内核协议栈的一个组件,其目的是充分运用传统内核协议栈已实现的较稳定的协议处理功能。DPDK平台对数据包的处理绕过了内核协议栈,直接交给用户空间处理,而用户空间没有完善的协议处理栈,如果让开发人员在用户空间实现完整独立的协议栈,开发工作是非常复杂的,因此DPDK平台提供了KNI组件,开发人员可以在用户空间实现一些特殊的协议处理功能,再通过KNI重入内核协议栈功能将普通常见的协议交由传统内核协议栈处理。


KNI通信机制

KNI组件通过创建KNI虚拟接口设备,将数据包经过虚拟接口实现用户空间和内核协议栈间的通信。当网卡接收到数据包时,应用程序通过用户空间驱动将数据包获取到用户空间,KNI组件将需要数据包发送至KNI虚拟接口,由KNI虚拟接口交给内核协议栈处理,处理后若有响应报文,则再交给KNI虚拟接口返回给应用程序。其中发送数据包至内核协议栈以及接收内核协议栈回复的数据包,是由两个不同的逻辑核分别进行处理,不阻塞应用程序让内核协议栈发送数据包或从内核协议栈接收数据包的过程。


KNI接口实际上是一个虚拟出来的设备,该虚拟设备定义了四个队列,分别是接收队列(rx_q)、发送队列(tx_q)、已分配内存块队列(alloc_q)、待释放内存块队列(free_q)。接收队列用于存放用户空间程序发往KNI虚拟设备的报文,发送队列用于存放内核协议栈要往KNI虚拟设备的报文。已分配内存块队列存放已向内存中申请的内存块,供内核协议栈发送报文时取出使用。待释放内存块队列用于记录KNI虚拟设备从用户空间程序处接收到报文后将不再使用的内存块,然后将该队列中的内存块释放回内存。用户空间程序从网卡接收到报文时,将报文发送给KNI虚拟设备,KNI虚拟设备接收到用户空间程序发来的报文后,交给内核协议栈进行协议解析。发送报文时,原始数据先由内核协议栈进行协议封装,然后将报文发送给KNI虚拟设备,KNI虚拟设备接收到报文后,再将报文发送给用户空间程序


4.5DKDP核心优化


DPDK的UIO驱动屏蔽了硬件发出的中断,然后在用户态采用主动轮训的方式,这种模式被称为PMD(Poll Mode Driver)


UIO 旁路了内核,主动轮训去掉硬中断,DPDK从而可以在用户态做收发包处理。带来zero copy,无系统调用的好处,同步处理减少上下文切换带来的Cache MIss。


运行在PMD的CORE会处于CPU100%的状态。


网络空闲时CPU 长期空转,会带来能耗问题。所以,DPDK推出interrupt DPDK模式。


interrupt DPDK:


DPDK的高性能代码实现


1.采用HugePage减少TLB Miss:默认下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。并提供了内存池(Mempool)、MBuf、无锁环(Ring)、Bitmap等基础库。根据我们的实践,在数据平面(Data Plane)频繁的内存分配释放,必须使用内存池,不能直接使用rte_malloc,DPDK的内存分配实现非常简陋,不如ptmalloc。


2. SNA(Shared-nothing Architecture)软件架构去中心化,尽量避免全局共享,带来全局竞争,失去横向扩展的能力。NUMA体系下不跨Node远程使用内存。


3. SIMD(Single Instruction Multiple Data)从最早的mmx/sse到最新的avx2,SIMD的能力一直在增强。DPDK采用批量同时处理多个包,再用向量编程,一个周期内对所有包进行处理。比如,memcpy就使用SIMD来提高速度。SIMD在游戏后台比较常见,但是其他业务如果有类似批量处理的场景,要提高性能,也可看看能否满足。


4. 不使用慢速API:这里需要重新定义一下慢速API,比如说gettimeofday,虽然在64位下通过vDSO已经不需要陷入内核态,只是一个纯内存访问,每秒也能达到几千万的级别。但是,不要忘记了我们在10GE下,每秒的处理能力就要达到几千万。所以即使是gettimeofday也属于慢速API。DPDK提供Cycles接口,例如rte_get_tsc_cycles接口,基于HPET或TSC实现。


五、DPDK视频教程


【DPDK高性能储存】dpdk从tcpip协议栈开始,准备好linux环境一起开始https://www.bilibili.com/video/BV1Sk4y1E7Bz/


【DPDk高性能储存】C/C++开发很好的技术方向,dpdk网络开发

https://www.bilibili.com/video/BV1Pc411M7Cx/


【DPDK高性能储存】dpdk的底层原理 ,让你可以开启另一个技术方向

https://www.bilibili.com/video/BV1uP41117gA/


【DPDK高性能储存】DPDK的前世今生,cc++程序员的未来方向

https://www.bilibili.com/video/BV1sT411b7Zw/


【DPDK高性能储存】dpdk的虚拟化,vhost与virtio的故事,走进qemu的实现原理https://www.bilibili.com/video/BV1nz4y1a7ji/


【DPDK高性能储存】nff-go与dpdk的那些故事,golang调用c的流程分析https://www.bilibili.com/video/BV1Ds4y1X7vo/


【DPDK高性能储存】5个dpdk的误区,用代码来解决,从dpdk手写协议栈开始https://www.bilibili.com/video/BV1cs4y197Gk/


【DPDK高性能储存】10个关于dpdkspdk开发的技术问题https://www.bilibili.com/video/BV12s4y1X7YE/


【DPDK高性能储存】fio的iops测试,为了fio手写一个spdk的引擎,(自备linux环境)https:www.bilibili.com/video/BV1Ca4y1g7Wh/


【DPDK高性能储存】vpp源码流程剖析,动态库加载,plugin,node,featrue流程https://www.bilibili.com/video/BV1Lz4y1a798/


【DPDK高性能储存】SPDK是如何实现高性能的,深入NVMe的工作原理https://www.bilibili.com/video/BV1eM41137mB/


【DPDK高性能储存】存储框架spdk,为技术栈打开一扇存储的大门https:www.bilibili.com/video/BV1P24y1M7tL/


【DPDK高性能储存】看懂6个问题,开启dpdk/spdk高性能开发之路https://www.bilibili.com/video/BV1BP41117Rg/


六、手写TCP/IP用户态协议栈(纯C语言)


(1)DPDK基础知识

  • 1、dpdk环境搭建与多队列网卡
  • 2、dpdk网卡绑定与arp
  • 3、dpdk发送过程的实现
  • 4、dpdk发送过程调试
  • 5、dpdk-arp实现
  • 6、arp 调试流程
  • 7、dpdk-icmp实现
  • 8、dpdk-icmp流程 调试与checksum实现
  • 9、arp-table的实现


(2)协议栈之udp/tcp的实现


  • 1、arp request实现
  • 2、arp调试流程
  • 3、协议栈架构设计优化
  • 4、udp实现之udp系统api的设计
  • 5、udp实现之sbuf与rbuf的环形队列
  • 6、udp实现之发送流程与并发解耦
  • 7、udp实现之架构设计与调试
  • 8、tcp 三次握手实现之dpdk tcp流程架构设计
  • 9、tcp三次握手实现之dpdk tcp11个状态实现
  • 10、tcp三次握手实现之dpdk代码调试


(3)协议栈之tcp的实现


  • 1、tcp数据传输之ack与seqnum的确认代码实现以及滑动窗口
  • 2、tcp数据传输之ack与seqnum代码实现以及滑动窗口
  • 3、tcp协议api实 现之bind, listen的实现
  • 4、tcp协议api实现之accept的实现
  • 5、tcp协议api实现之send, recv的实现
  • 6、tcp协议api实 现之close的实现
  • 7、tcp协议栈调试之段错误与逻辑流程
  • 8、tcp协议栈调试之ringbuffer内存错误.
  • 9、dpdk kni的原理与kni启动
  • 10、重构网络协议分发的流程


(4)协议栈的组件功能


  • 1、kni抓包调试tcpdump
  • 2、dpdk kni mempool错误与内存泄漏
  • 3、基于熵的ddos检测的数学理论
  • 4、dpdk ddos熵计算代码实现
  • 5、dpdkddosattach检测准确度调试
  • 6、ddos attack测试工具hping3
  • 7、dpdk布谷鸟hash原理与使用


(5)协议栈之tcp并发实现


  • 1、tcp并发连接的设计
  • 2、tcp并发epoll的实现
  • 3、tcp并 发协议栈与epoll的回调与并发测试
  • 4、bpf与bpftrace系统,网络挂载实现
  • 5、bpf与 bpftrace应用程序ntyco的挂载监控


(6)DPDK网络基础组件

  • 1、mempool与mbuf的源码分析讲解
  • 2、dpdk-ringbuffer源码分 析
  • 3、dpdk-igb_ uio源码分 析
  • 4、dpdk-kni源码分析
  • 5、rcu的实现与互斥锁,自旋锁,读写锁


解决问题


  • 1、苦读网络书籍没有实际项目运用
  • 2、简历没有合适的网络项目可写
  • 3、有C基础,纯兴趣爱好


手写3000行代码,让你掌握网络通信核心技术。


七、DPDK市场发展


DPDK的大多数应用最初是在电信领域。随着CSP采用网络虚拟化来降低运营成本并加快新服务的部署,他们虚拟化了需要高吞吐量和/或低延迟的用例,例如路由器,防火墙,无线电访问网络(RAN)和演进的分组核心(EPC)。虚拟化平台的供应商,在这些情况下,VNF和应用程序已在其产品中利用了DPDK,以实现CSP的性能目标。随着CSP探索新的边缘托管应用,例如视频缓存,监控,增强现实(AR),辅助驾驶,零售和工业物联网,DPDK仍然是实现积极性能目标的关键技术。


类似DPDK最先在电信应用程序中, 对数据包处理功能的性能要求一样, DPDK越来越多地应用于企业和云当中。例如,在2018年,VMware引入了他们的NSX-T数据中心软件定义基础结构的基于DPDK的边缘配置。此版本的NSX-T地址需要具有可变数据包大小的高数据包吞吐量的应用程序以及支持具有以下功能的高速NIC的服务器高达100Gbps的北/南流量。通常,南北向流的包大小各不相同,数据包处理要求,即使它们只占总流量的不到20%。在此用例中,通过使用带有小数据包(64字节)的DPDK,英特尔和VMware的分析表明,性能提高了五倍。


同时有几家公司已将DPDK用于金融应用,其中低延迟带来了巨大的竞争优势。例如,在高频交易(HFT)中,延迟会直接影响交易者的交易效率 算法策略及其超越竞争对手的能力。信息周刊估计,对于一家大型经纪公司来说,一毫秒每年价值1亿美元。DPDK是这个市场解决方案供应商开发所依赖的关键技术。


写在最后:

Dpdk作为目前在互联网越来越流行的底层技术,受到越来越多的优秀互联网公司的欢迎与使用。但对于不少程序员来说可能只是见过或是听过,并没有深入的学习和使用。如果你也是对dpdk感兴趣或是有往dpdk工程师岗位方向的朋友们可以了解一下【零声教育】的【dpdk/网络协议栈/vpp/OvS/DDos/SDN/NFV/虚拟化/高性能专家之路https://ke.qq.com/course/5066203?flowToken=1043213】系统课程。


相关文章
|
18天前
|
负载均衡 算法 应用服务中间件
面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
字节跳动面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
32 0
|
2天前
|
缓存 网络协议 网络架构
【计算机网络】第三章 数据链路层(MAC地址 IP地址 ARP协议)
【计算机网络】第三章 数据链路层(MAC地址 IP地址 ARP协议)
|
3天前
|
存储 网络协议 关系型数据库
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
|
3天前
|
SQL 安全 测试技术
2021年职业院校技能大赛“网络安全”项目 江西省比赛任务书—B模块
B模块涵盖安全事件响应和网络数据取证,涉及多项应用安全挑战。任务包括使用nmap扫描靶机、弱口令登录、生成反弹木马、权限验证、系统内核版本检查、漏洞源码利用、文件名和内容提取等。此外,还有Linux渗透测试,要求访问特定目录下的文件并提取内容。应用服务漏洞扫描涉及服务版本探测、敏感文件发现、私钥解密、权限提升等。SQL注入测试需利用Nmap扫描端口,进行SQL注入并获取敏感信息。应急响应任务包括处理木马、删除恶意用户、修复启动项和清除服务器上的木马。流量分析涉及Wireshark数据包分析,查找黑客IP、枚举测试、服务破解等。渗透测试任务涵盖系统服务扫描、数据库管理、漏洞利用模块搜索等。
11 0
|
8天前
|
安全 网络安全 网络虚拟化
如何保护IP在线隐私,提高网络安全?
如何保护IP在线隐私,提高网络安全?
|
9天前
|
JSON 网络协议 API
Python网络编程面试题精讲
【4月更文挑战第15天】本文介绍了Python网络编程的面试重点,包括基础Socket编程、HTTP协议与requests库、异步编程与asyncio库。通过实例解析常见面试题,强调了非阻塞套接字、异常处理、HTTP状态码检查以及异步任务管理等关键点。提供代码示例帮助读者巩固概念,助力面试准备。
16 0
|
9天前
|
缓存 安全 网络协议
代理ip会不会影响网络速度和稳定性
代理ip会不会影响网络速度和稳定性
|
10天前
|
网络协议 网络安全 网络虚拟化
网络面试题
网络面试题
|
10天前
|
网络协议 Java API
深度剖析:Java网络编程中的TCP/IP与HTTP协议实践
【4月更文挑战第17天】Java网络编程重在TCP/IP和HTTP协议的应用。TCP提供可靠数据传输,通过Socket和ServerSocket实现;HTTP用于Web服务,常借助HttpURLConnection或Apache HttpClient。两者结合,构成网络服务基础。Java有多种高级API和框架(如Netty、Spring Boot)简化开发,助力高效、高并发的网络通信。
|
11天前
|
存储 网络协议 安全
15.网络协议-Radius协议
15.网络协议-Radius协议