-
1、传统网络架构
传统的网络设备(交换机、路由器等)为了快速处理数据包而嵌入了NP处理器(Network Process),内置硬件电路实现高速转发数据包。随着云计算的发展以CPU为核心、操作系统是linux,网络设备都是虚拟化,没有NP处理器。云计算需要高速的处理数据包的要求。传统的网络架构处理流程如下:
传统网络框架处理流程中没有控制层面和数据层面之分,大部分的处理都是在内核中完成。传统网络架构的劣势如下:
(1)当收到大量数据包就会频繁产生硬件中断,硬件中断就会打断优先级较低的软件中断,从而存在频繁的切换损耗性能。
(2)网卡收到数据包在内核经过协议栈处理要拷贝到应用层缓冲区,这样的拷贝很耗时间,据统计这个拷贝的时间占数据包处理 流程时间的57.1%。
(3)频繁到达的硬件中断和软中断都可能随时抢占系统调用的运行,这会产生大量的上下文切换开销。另外,在基于多线程的服务器设计框架中,线程间的调度也会产生频繁的上下文切换开销,同样,锁竞争的耗能也是一个非常严重的问题。
(4)如今主流的处理器都是多个核心的,这意味着一个数据包的处理可能跨多个 CPU 核心,比如一个数据包可能中断在 cpu0,内核态处理在 cpu1,用户态处理在 cpu2,这样跨多个核心,容易造成 CPU 缓存失效,造成局部性失效。如果是 NUMA 架构,更会造成跨 NUMA 访问内存,性能受到很大影响。
(5)传统服务器内存页为 4K,为了提高内存的访问速度,避免 cache miss,可以增加 cache 中映射表的条目,但这又会影响 CPU 的检索效率。
-
2、dpdk
dpdk 全称data plane development kit(数据平面转发工具),为 Intel 处理器架构下用户空间高效的数据包处理提供了库函数和驱动的支持,数据包的控制层和数据层分开,dpdk绕过linux内核协议栈将数据包的接受处理放到应用层。
DPDK拦截中断,不触发后续中断流程,并绕过协议栈,通过UIO技术将网卡收到的报文拷贝到应用层处理,报文不再经过内核协议栈。减少了中断,DPDK的包全部在用户控件使用内存池管理,内核控件与用户空间的内存交互不用进行拷贝,只做控制权转移,减少报文拷贝过程,提高报文的转发效率。
如上图所示dpkd总体框架图,底层通过UIO技术来实现用户态和内核态的数据包交互,然后将数据包的控制器交给应用层的应用程序处理,dpdk只是一个框架它提供各种功能库比如:MEMORY、RING、MBUF、PDM、MEMPOOL,这些接下来会分析。
dpkd主要有以下核心技术:
(1)UIO
UIO是用户空间的一种I/O技术,dpdk 能够绕过内核协议栈,本质上是得益于 UIO 技术,通过 UIO 能够拦截中断,并重设中断回调行为,从而绕过内核协议栈后续的处理流程。
UIO 设备的实现机制其实是对用户空间暴露文件接口,比如当注册一个 UIO 设备 uioX,就会出现文件 /dev/uioX,对该文件的读写就是对设备内存的读写。除此之外,对设备的控制还可以通过 /sys/class/uio 下的各个文件的读写来完成。
(2)内存池技术
dpdk 在用户空间实现了一套精巧的内存池技术,内核空间和用户空间的内存交互不进行拷贝,只做控制权转移。这样,当收发数据包时,就减少了内存拷贝的开销。
(3)大页内存分配
dpdk 实现了一组大页内存分配、使用和释放的 API,上层应用可以很方便使用 API 申请使用大页内存,同时也兼容普通的内存申请,通过更大的内存页(如1G内存页),减少TLB(Translation Lookaside Buffer,即快表) Miss,Miss对报文转发性能影响很大
(4)无锁循环队列
dpdk 基于 Linux 内核的无锁环形缓冲 kfifo 实现了自己的一套无锁机制。支持单生产者入列/单消费者出列和多生产者入列/多消费者出列操作,在数据传输的时候,降低性能的同时还能保证数据的同步。
(5)PDM
DPDK网卡驱动完全抛弃中断模式,基于轮询方式收包,避免了中断开销,简称PDM。
(6)NUMA
dpdk 内存分配上通过 proc 提供的内存信息,使 CPU 核心尽量使用靠近其所在节点的内存,避免了跨 NUMA 节点远程访问内存的性能问题.
(7)CPU亲和力
dpdk 利用 CPU 的亲和性将一个线程或多个线程绑定到一个或多个 CPU 上,这样在线程执行过程中,就不会被随意调度,一方面减少了线程间的频繁切换带来的开销,另一方面避免了 CPU 缓存的局部失效性,增加了 CPU 缓存的命中率。
DPDK将网卡接收队列分配给某个CPU核,该队列收到的报文都交给该核上的DPDK线程处理。存在两种方式将数据包发送到接收队列之上:
RSS(Receive Side Scaling,接收方扩展)机制:根据关键字,比如根据UDP的四元组<srcIP><dstIP><srcPort><dstPort>进行哈希
Flow Director机制:可设定根据数据包某些信息进行精确匹配,分配到指定的队列与CPU核
当网络数据包(帧)被网卡接收后,DPDK网卡驱动将其存储在一个高效缓冲区中,并在MBUF缓存中创建MBUF对象与实际网络包相连,对网络包的分析和处理都会基于该MBUF,必要的时候才会访问缓冲区中的实际网络包
(8)多核调度框架
dpdk 基于多核架构,一般会有主从核之分,主核负责完成各个模块的初始化,从核负责具体的业务处理。
-
3、dpdk核心组件
核心组件 指一系列的库,用于为高性能包处理程序提供所有必须的元素。核心组件及其之间的关系如下图所示
(1)环形缓冲区管理(librte_ring)
Ring数据结构提供了一个无锁的多生产者,多消费者的FIFO表处理接口。 他比无锁队列优异的地方在于它容易部署,适合大量的操作,而且更快。 Ring库在 Memory Pool Manager (librte_mempool)中使用到, 而且ring还用于不同核之间或是逻辑核上处理单元之间的通信。
(2)内存池管理(librte_mempool)
内存池管理的主要职责就是在内存中分配指定数目对象的POOL。 每个POOL以名称来唯一标识,并且使用一个ring来存储空闲的对象节点。 它还提供了一些其他的服务如对象节点的每核备份缓存及自动对齐以保证元素能均衡的处于每核内存通道上。
(3) 网络报文缓冲区管理(librte_mbuf)
报文缓存管理器提供了创建、释放报文缓存的能力,DPDK应用程序中可能使用这些报文缓存来存储消息。 而消息通常在程序开始时通过DPDK的MEMPOOL库创建并存储。 BUFF库提供了报文申请释放的API,通常消息buff用于缓存普通消息,报文buff用于缓存网络报文。
(4)定时器管理(librte_timer)
这个库位DPDK执行单元提供了定时服务,为函数异步执行提供支持。 定时器可以设置周期调用或只调用一次。 使用EAL提供的接口获取高精度时钟,并且能在每个核上根据需要初始化。
(5)以太网轮询驱动架构
DPDK的PMD驱动支持1G、10G、40G。 同时DPDK提供了虚拟的以太网控制器,被设计成非异步,基于中断的模式。
(6)报文转发算法支持
DPDK提供了哈希(librte_hash)、最长前缀匹配的(librte_lpm)算法库用于支持包转发。
(7)网络协议库(librte_net)
这个库提供了IP协议的一些定义,以及一些常用的宏。 这些定义都基于FreeBSD IP协议栈的代码,并且包含相关的协议号,IP相关宏定义,IPV4和IPV6头部结构等等。