1.2 初识DPDK
本书介绍DPDK,主要以IA(Intel Architecture)多核处理器为目标平台。在IA上,网络数据包处理远早于DPDK而存在。从商业版的Windows到开源的Linux操作系统,所有跨主机通信几乎都会涉及网络协议栈以及底层网卡驱动对于数据包的处理。然而,低速网络与高速网络处理对系统的要求完全不一样。
1.2.1 IA不适合进行数据包处理吗
以Linux为例,传统网络设备驱动包处理的动作可以概括如下:
- 数据包到达网卡设备。
- 网卡设备依据配置进行DMA操作。
- 网卡发送中断,唤醒处理器。
- 驱动软件填充读写缓冲区数据结构。
- 数据报文达到内核协议栈,进行高层处理。
- 如果最终应用在用户态,数据从内核搬移到用户态。
- 如果最终应用在内核态,在内核继续进行。
随着网络接口带宽从千兆向万兆迈进,原先每个报文就会触发一个中断,中断带来的开销变得突出,大量数据到来会触发频繁的中断开销,导致系统无法承受,因此有人在Linux内核中引入了NAPI机制,其策略是系统被中断唤醒后,尽量使用轮询的方式一次处理多个数据包,直到网络再次空闲重新转入中断等待。NAPI策略用于高吞吐的场景,效率提升明显。
一个二层以太网包经过网络设备驱动的处理后,最终大多要交给用户态的应用,图1-4的典型网络协议层次OSI与TCP/IP模型,是一个基础的网络模型与层次,左侧是OSI定义的7层模型,右侧是TCP/IP的具体实现。网络包进入计算机大多需要经过协议处理,在Linux系统中TCP/IP由Linux内核处理。即使在不需要协议处理的场景下,大多数场景下也需要把包从内核的缓冲区复制到用户缓冲区,系统调用以及数据包复制的开销,会直接影响用户态应用从设备直接获得包的能力。而对于多样的网络功能节点来说,TCP/IP协议栈并不是数据转发节点所必需的。
以无线网为例,图1-5的无线4G/LTE数据面网络协议展示了从基站、基站控制器到无线核心网关的协议层次,可以看到大量处理是在网络二、三、四层进行的。如何让Linux这样的面向控制面原生设计的操作系统在包处理上减少不必要的开销一直是一大热点。有个著名的高性能网络I/O框架Netmap,它就是采用共享数据包池的方式,减少内核到用户空间的包复制。
NAPI与Netmap两方面的努力其实已经明显改善了传统Linux系统上的包处理能力,那是否还有空间去做得更好呢?作为分时操作系统,Linux要将CPU的执行时间合理地调度给需要运行的任务。相对于公平分时,不可避免的就是适时调度。早些年CPU核数比较少,为了每个任务都得到响应处理,进行充分分时,用效率换响应,是一个理想的策略。现今CPU核数越来越多,性能越来越强,为了追求极端的高性能高效率,分时就不一定总是上佳的策略。以Netmap为例,即便其减少了内核到用户空间的内存复制,但内核驱动的收发包处理和用户态线程依旧由操作系统调度执行,除去任务切换本身的开销,由切换导致的后续cache替换(不同任务内存热点不同),对性能也会产生负面的影响。
如果再往实时性方面考虑,传统上,事件从中断发生到应用感知,也是要经过长长的软件处理路径。所以,在2010年前采用IA处理器的用户会得出这样一个结论,那就是IA不适合做包处理。
真的是这样么?在IA硬件基础上,包处理能力到底能做到多好,有没有更好的方法评估和优化包处理性能,怎样的软件设计方法能最充分地释放多核IA的包处理能力,这些问题都是在DPDK出现之前,实实在在地摆在Intel工程师面前的原始挑战。
1.2.2 DPDK最佳实践
如今,DPDK应该已经很好地回答了IA多核处理器是否可以应对高性能数据包处理这个问题。而解决好这样一个问题,也不是用了什么凭空产生的特殊技术,更多的是从工程优化角度的迭代和最佳实践的融合。如果要简单地盘点一下这些技术,大致可以归纳如下。
轮询,这一点很直接,可避免中断上下文切换的开销。之前提到Linux也采用该方法改进对大吞吐数据的处理,效果很好。在第7章,我们会详细讨论轮询与中断的权衡。
用户态驱动,在这种工作方式下,既规避了不必要的内存拷贝又避免了系统调用。一个间接的影响在于,用户态驱动不受限于内核现有的数据格式和行为定义。对mbuf头格式的重定义、对网卡DMA操作的重新优化可以获得更好的性能。而用户态驱动也便于快速地迭代优化,甚至对不同场景进行不同的优化组合。在第6章中,我们将探讨用户态网卡收发包优化。
亲和性与独占,DPDK工作在用户态,线程的调度仍然依赖内核。利用线程的CPU亲和绑定的方式,特定任务可以被指定只在某个核上工作。好处是可避免线程在不同核间频繁切换,核间线程切换容易导致因cache miss和cache write back造成的大量性能损失。如果更进一步地限定某些核不参与Linux系统调度,就可能使线程独占该核,保证更多cache hit的同时,也避免了同一个核内的多任务切换开销。在第3章,我们会再展开讨论。
降低访存开销,网络数据包处理是一种典型的I/O密集型(I/O bound)工作负载。无论是CPU指令还是DMA,对于内存子系统(Cache+DRAM)都会访问频繁。利用一些已知的高效方法来减少访存的开销能够有效地提升性能。比如利用内存大页能有效降低TLB miss,比如利用内存多通道的交错访问能有效提高内存访问的有效带宽,再比如利用对于内存非对称性的感知可以避免额外的访存延迟。而cache更是几乎所有优化的核心地带,这些有意思而且对性能有直接影响的部分,将在第2章进行更细致的介绍。
软件调优,调优本身并不能说是最佳实践。这里其实指代的是一系列调优实践,比如结构的cache line对齐,比如数据在多核间访问避免跨cache line共享,比如适时地预取数据,再如多元数据批量操作。这些具体的优化策略散布在DPDK各个角落。在第2章、第6章、第7章都会具体涉及。
利用IA新硬件技术,IA的最新指令集以及其他新功能一直是DPDK致力挖掘数据包处理性能的源泉。拿Intel? DDIO技术来讲,这个cache子系统对DMA访存的硬件创新直接助推了性能跨越式的增长。有效利用SIMD(Single Instruction Multiple Data)并结合超标量技术(Superscalar)对数据层面或者对指令层面进行深度并行化,在性能的进一步提升上也行之有效。另外一些指令(比如cmpxchg),本身就是lockless数据结构的基石,而crc32指令对与4 Byte Key的哈希计算也是改善明显。这些内容,在第2章、第4章、第5章、第6章都会有涉及。
充分挖掘网卡的潜能,经过DPDK I/O加速的数据包通过PCIe网卡进入系统内存,PCIe外设到系统内存之间的带宽利用效率、数据传送方式(coalesce操作)等都是直接影响I/O性能的因素。在现代网卡中,往往还支持一些分流(如RSS,FDIR等)和卸载(如Chksum,TSO等)功能。DPDK充分利用这些硬件加速特性,帮助应用更好地获得直接的性能提升。这些内容将从第6章~第9章一一展开。
除了这些基础的最佳实践,本书还会用比较多的篇幅带领大家进入DPDK I/O虚拟化的世界。在那里,我们依然从I/O的视角,介绍业界广泛使用的两种主流方式,SR-IOV和Virtio,帮助大家理解I/O硬件虚拟化的支撑技术以及I/O软件半虚拟化的技术演进和革新。从第10章到第14章,我们会围绕着这一主题逐步展开。
随着DPDK不断丰满成熟,也将自身逐步拓展到更多的平台和场景。从Linux到FreeBSD,从物理机到虚拟机,从加速网络I/O到加速存储I/O,DPDK在不同纬度发芽生长。在NFV大潮下,无论是NFVI(例如,virtual switch)还是VNF,DPDK都用坚实有力的性能来提供基础设施保障。这些内容将在第10章~第15章一一介绍。
当然,在开始后续所有章节之前,让我们概览一下DPDK的软件整体框架。
1.2.3 DPDK框架简介
DPDK为IA上的高速包处理而设计。图1-6所示的DPDK主要模块分解展示了以基础软件库的形式,为上层应用的开发提供一个高性能的基础I/O开发包。它大量利用了有助于包处理的软硬件特性,如大页、缓存行对齐、线程绑定、预取、NUMA、IA最新指令的利用、Intel? DDIO、内存交叉访问等。
核心库Core Libs,提供系统抽象、大页内存、缓存池、定时器及无锁环等基础组件。
PMD库,提供全用户态的驱动,以便通过轮询和线程绑定得到极高的网络吞吐,支持各种本地和虚拟的网卡。
Classify库,支持精确匹配(Exact Match)、最长匹配(LPM)和通配符匹配(ACL),提供常用包处理的查表操作。
QoS库,提供网络服务质量相关组件,如限速(Meter)和调度(Sched)。
除了这些组件,DPDK还提供了几个平台特性,比如节能考虑的运行时频率调整(POWER),与Linux kernel stack建立快速通道的KNI(Kernel Network Interface)。而Packet Framework和DISTRIB为搭建更复杂的多核流水线处理模型提供了基础的组件。
1.2.4 寻找性能优化的天花板
性能优化不是无止境的,所谓天花板可以认为是理论极限,性能优化能做到的就是无限接近这个理论极限。而理论极限也不是单纬度的,当某个纬度接近极限时,可能在另一个纬度会有其他的发现。
我们讨论数据包处理,那首先就看看数据包转发速率是否有天花板。其实包转发的天花板就是理论物理线路上能够传送的最大速率,即线速。那数据包经过网络接口进入内存,会经过I/O总线(例如,PCIe bus),I/O总线也有天花板,实际事务传输不可能超过总线最大带宽。CPU从cache里加载/存储cache line有没有天花板呢,当然也有,比如Haswell处理器能在一个周期加载64字节和保存32字节。同样内存控制器也有内存读写带宽。这些不同纬度的边界把工作负载包裹起来,而优化就是在这个边界里吹皮球,不断地去接近甚至触碰这样的边界。
由于天花板是理论上的,因此对于前面介绍的一些可量化的天花板,总是能够指导并反映性能优化的优劣。而有些天花板可能很难量化,比如在某个特定频率的CPU下每个包所消耗的周期最小能做到多少。对于这样的天花板,可能只能用不断尝试实践的方式,当然不同的方法可能带来不同程度的突破,总的增益越来越少时,就可能是接近天花板的时候。
那DPDK在IA上提供网络处理能力有多优秀呢?它是否已经能触及一些系统的天花板?在这些天花板中,最难触碰的是哪一个呢?要真正理解这一点,首先要明白在IA上包处理终极挑战的问题是什么,在这之前我们需要先来回顾一下衡量包处理能力的一些常见能力指标