对于用户来说,它可能是一个性能出色的包数据处理加速软件库;对于开发者来说,它可能是一个实践包处理新想法的创新工场;对于性能调优者来说,它可能又是一个绝佳的成果分享平台。
DPDK用软件的方式在通用多核处理器上演绎着数据包处理的新篇章,而对于数据包处理,多核处理器显然不是唯一的平台。支撑包处理的主流硬件平台大致可分为三个方向:硬件加速器、网络处理器、多核处理器。
根据处理内容、复杂度、成本、量产规模等因素的不同,这些平台在各自特定的领域都有一定的优势。 硬件加速器对于本身规模化的固化功能具有高性能低成本的特点,网络处理器提供了包处理逻辑软件可编程的能力,在获得灵活性的同时兼顾了高性能的硬件包处理,多核处理器在更为复杂多变的高层包处理上拥有优势,随着包处理的开源生态系统逐渐丰富,以及近年来性能的不断提升,其为软件定义的包处理提供了快速迭代的平台。
随着现代处理器的创新与发展(如异构化),开始集成新的加速处理与高速IO单元,它们互相之间不断地融合。 在一些多核处理器中,已能看到硬件加速单元的身影。 从软件包处理的角度,可以卸载部分功能到那些硬件加速单元进一步提升性能瓶颈;从硬件包处理的流水线来看,多核上运行的软件完成了难以固化的上层多变逻辑的任务;二者相得益彰。
在类似 IA(Intel Architecture)多核处理器为目标的平台上,网络数据包处理远早于DPDK而存在。从商业版的 Windows到开源的Linux操作系统,所有跨主机通信几乎都会涉及网络协议栈以及底层网卡驱动对于数据包的处理。然而,低速网络与高速网络处理对系统的要求完全不一样。
硬件加速器被广泛应用于包处理领域, ASIC和FPGA是其中最广为采用的器件。ASIC(Application-Specific Integrated Circuit)是一种应特定用户要求和特定电子系统的需要而设计、制造的集成电路。 ASIC的优点是面向特定用户的需求,在批量生产时与通用集成电路相比体积更小、功耗更低、可靠性提高、性能提高、保密性增强、成本降低等。 但ASIC的缺点也很明显,它的灵活性和扩展性不够、开发费用高、开发周期长。为了弥补本身的一些缺点, ASIC越来越多地按照加速引擎的思路来构建,结合通用处理器的特点,融合成片上系统(SoC)提供异构处理能力,使得ASIC带上了智能(Smart)的标签。
FPGA(Field-Programmable Gate Array)即现场可编程门阵列。 它作为ASIC领域中的一种半定制电路而出现,与ASIC的区别是用户不需要介入芯片的布局布线和工艺问题,而且可以随时改变其逻辑功能,使用灵活。 FPGA以并行运算为主,其开发相对于传统PC、单片机的开发有很大不同,以硬件描述语言(Verilog或VHDL)来实现。 相比于PC或单片机(无论是冯·诺依曼结构还是哈佛结构)的顺序操作有很大区别。全可编程FPGA概念的提出,使FPGA朝着进一步软化的方向持续发展,其并行化整数运算的能力将进一步在通用计算定制化领域得到挖掘,近年来在数据中心中取得了很大进展,比如应用于机器学习场合。我们预计FPGA在包处理的应用场景将会从通信领域(CT)越来越多地走向数据中心和云计算领域。
网络处理器(Network Processer Unit, NPU)是专门为处理数据包而设计的可编程通用处理器,采用多内核并行处理结构,其常被应用于通信领域的各种任务,比如包处理、协议分析、路由查找、声音/数据的汇聚、防火墙、 QoS等。 其通用性表现在执行逻辑由运行时加载的软件决定,用户使用专用指令集即微码(microcode)进行开发。 其硬件体系结构大多采用高速的接口技术和总线规范,具有较高的I/O能力,使得包处理能力得到很大提升。 除了这些特点外, NPU一般还包含多种不同性能的存储结构,对数据进行分类存储以适应不同的应用目的。NPU中也越来越多地集成进了一些专用硬件协处理器,可进一步提高片内系统性能。
NP-5处理器架构框图,以EZCHIP公司的NP-5处理器架构为例, TOP部分为可编程部分,根据需要通过编写微码快速实现业务相关的包处理逻辑。 NPU拥有高性能和高可编程性等诸多优点,但其成本和特定领域的特性限制了它的市场规模(一般应用于专用通信设备)。而不同厂商不同架构的NPU遵循的微码规范不尽相同,开发人员的成长以及生态系统的构建都比较困难。 虽然一些NPU的微码也开始支持由高级语言(例如C)编译生成,但由于结构化语言本身原语并未面向包处理,使得转换后的效率并不理想。
随着SDN对于可编程网络,特别是可编程数据面的要求,网络处理器也可能会迎来新的发展机遇,但依然需要解决好不同架构的底层抽象以及上层业务的语义抽象。
现代CPU性能的扩展主要通过多核的方式进行演进。 这样利用通用处理器同样可以在一定程度上并行地处理网络负载。 由于多核处理器在逻辑负载复杂的协议及应用层面上的处理优势,以及越来越强劲的数据面的支持能力,它在多种业务领域得到广泛的采用。 再加上多年来围绕CPU已经建立起的大量成熟软件生态,多核处理器发展的活力和热度也是其他形态很难比拟的。 图1-2是Intel双路服务器平台框图,描述了一个典型的双路服务器平台的多个模块, CPU、芯片组C612、内存和以太网控制器XL710构成了主要的数据处理通道。 基于PCIe总线的I/O接口提供了大量的系统接口,为服务器平台引入了差异化的设计。当前的多核处理器也正在走向SoC化,针对网络的SoC往往集成内存控制器、网络控制器,甚至是一些硬件加速处理引擎。这里列出了一些主流厂商的多核处理器的SoC平台:IA multi-core Xeon、Tilear-TILE-Gx、Cavium Network-OCTEON&OCTEON II、Freescale-QorIQ、NetLogic Microsystem-XLP。
Cavium OCTEON处理器框图以Cavium OCTEON多核处理器为例,它集成多个CPU核以及众多加速单元和网络接口,组成了一个片上系统(SoC)。在这些SoC上,对于可固化的处理(例如,流分类, QoS)交由加速单元完成,而对于灵活的业务逻辑则由众多的通用处理器完成,这种方式有效地融合了软硬件各自的优势。 随着软件(例如, DPDK)在I/O性能提升上的不断创新,将多核处理器的竞争力提升到一个前所未有的高度,网络负载与虚拟化的融合又催生了NFV的潮流。
网络设备(路由器、交换机、媒体网关、SBC、PS网关等)需要在瞬间进行大量的报文收发,因此在传统的网络设备上,往往能够看到专门的NP(Network Process)处理器,有的用FPGA,有的用ASIC。这些专用器件通过内置的硬件电路(或通过编程形成的硬件电路)高效转发报文,只有需要对报文进行深度处理的时候才需要CPU干涉。
但在公有云、NFV等应用场景下,基础设施以CPU为运算核心,往往不具备专用的NP处理器,操作系统也以通用Linux为主,网络数据包的收发处理路径如下图所示:
在虚拟化环境中,路径则会更长:
由于包处理任务存在内核态与用户态的切换,以及多次的内存拷贝,系统消耗变大,以CPU为核心的系统存在很大的处理瓶颈。为了提升在通用服务器(COTS)的数据包处理效能,Intel推出了服务于IA(Intel Architecture)系统的DPDK技术。
DPDK是Data Plane Development Kit的缩写。简单说,DPDK应用程序运行在操作系统的User Space,利用自身提供的数据面库进行收发包处理,绕过了Linux内核态协议栈,以提升报文处理效率。
ACL:Access Control List,访问控制列表,是路由器和交换机接口的指令列表,用来控制端口进出的数据包;简而言之就是用来控制数据流。
SSL:Secure Sockets Layer,安全套接层,是为网络通信提供安全及数据完整性的一种安全协议,在传输层对网络连接进行加密。
RSS:Receive Side Scaling,是一种能够在多处理器系统下使接收报文在多个CPU之间高效分发的网卡驱动技术。
NUMA:Non Uniform Memory Access Architecture,非统一内存访问架构;
QOS:Quality of Service,服务质量,指一个网络能够利用各种基础技术,为指定的网络通信提供更好的服务能力,是网络的一种安全机制,是用来解决网络延迟和阻塞等问题的一种技术。
NIC:Network Interface Card,网卡,网卡是局域网中最基本的部件之一,它是连接计算机与网络的硬件设备。
PCI:Peripheral Component Interconnect,计算机一种标准总线,NIC就是使用的这种总线方式。
PMD:Poll Mode Drive,轮询模式驱动,DPDK就是采用的这种模式。
RTE:Run Time Environment,通过PMD实现快速分组处理数据的一个框架。
MPLS:Multi-Protocol Label Switching,多协议标签交换,是一种用于快速数据包交换和路由的体系,它为网络数据流量提供了目标、路由地址、转发和交换等能力。更特殊的是,它具有管理各种不同形式通信流的机制。
以Linux为例,传统网络设备驱动包处理的动作可以概括如下:数据包到达网卡设备、网卡设备依据配置进行DMA操作、网卡发送中断,唤醒处理器、驱动软件填充读写缓冲区数据结构、数据报文达到内核协议栈,进行高层处理、如果最终应用在用户态,数据从内核搬移到用户态、如果最终应用在内核态,在内核继续进行。
随着网络接口带宽从千兆向万兆迈进,原先每个报文就会触发一个中断,中断带来的开销变得突出,大量数据到来会触发频繁的中断开销,导致系统无法承受,因此有人在Linux内核中引入了NAPI机制,其策略是系统被中断唤醒后,尽量使用轮询的方式一次处理多个数据包,直到网络再次空闲重新转入中断等待。 NAPI策略用于高吞吐的场景,效率提升明显。一个二层以太网包经过网络设备驱动的处理后,最终大多要交给用户态的应用,下图典型网络协议层次OSI与TCP/IP模型,是一个基础的网络模型与层次,左侧是OSI定义的7层模型,右侧是TCP/IP的具体实现。 网络包进入计算机大多需要经过协议处理,在Linux系统中TCP/IP由Linux内核处理。 即使在不需要协议处理的场景下,大多数场景下也需要把包从内核的缓冲区复制到用户缓冲区,系统调用以及数据包复制的开销,会直接影响用户态应用从设备直接获得包的能力。 而对于多样的网络功能节点来说, TCP/IP协议栈并不是数据转发节点所必需的。
以无线网为例,下图的无线4G/LTE数据面网络协议展示了从基站、基站控制器到无线核心网关的协议层次,可以看到大量处理是在网络二、三、四层进行的。 如何让Linux这样的面向控制面原生设计的操作系统在包处理上减少不必要的开销一直是一大热点。 有个著名的高性能网络I/O框架Netmap,它就是采用共享数据包池的方式,减少内核到用户空间的包复制。
NAPI与Netmap两方面的努力其实已经明显改善了传统Linux系统上的包处理能力,那是否还有空间去做得更好呢? 作为分时操作系统,Linux要将CPU的执行时间合理地调度给需要运行的任务。 相对于公平分时,不可避免的就是适时调度。 早些年CPU核数比较少,为了每个任务都得到响应处理,进行充分分时,用效率换响应,是一个理想的策略。 现今CPU核数越来越多,性能越来越强,为了追求极端的高性能高效率,分时就不一定总是上佳的策略。 以Netmap为例,即便其减少了核到用户空间的内存复制,但内核驱动的收发包处理和用户态线程依旧由操作系统调度执行,除去任务切换本身的开销,由切换导致的后续cache替换(不同任务内存热点不同),对性能也会产生负面的影响。如果再往实时性方面考虑,传统上,事件从中断发生到应用感知,也是要经过长长的软件处理路径。 所以,在2010年前采用IA处理器的用户会得出这样一个结论,那就是IA不适合做包处理。真的是这样么? 在IA硬件基础上,包处理能力到底能做到多好,有没有更好的方法评估和优化包处理性能,怎样的软件设计方法能最充分地释放多核IA的包处理能力,这些问题都是在DPDK出现之前,实实在在地摆在Intel工程师面前的原始挑战。
DPDK为IA上的高速包处理而设计。
如下图所示,DPDK主要模块分解展示了以基础软件库的形式,为上层应用的开发提供一个高性能的基础I/O开发包。它大量利用了有助于包处理的软硬件特性,如大页、缓存行对齐、线程绑定、预取、NUMA、IA最新指令的利用、Intel DDIO、内存交叉访问等。
核心库Core Libs,提供系统抽象、大页内存、缓存池、定时器及无锁环等基础组件。
PMD库,提供全用户态的驱动,以便通过轮询和线程绑定得到极高的网络吞吐,支持各种本地和虚拟的网卡。
Classify库,支持精确匹配(Exact Match)、最长匹配(LPM)和通配符匹配(ACL),提供常用包处理的查表操作。
QoS库,提供网络服务质量相关组件,如限速(Meter)和调度(Sched)。
如今, DPDK应该已经很好地回答了IA多核处理器是否可以应对高性能数据包处理这个问题。 而解决好这样一个问题,也不是用了什么凭空产生的特殊技术,更多的是从工程优化角度的迭代和最佳实践的融合。 如果要简单地盘点一下这些技术,大致可以归纳如下。
轮询:这一点很直接,可避免中断上下文切换的开销。 之前提到Linux也采用该方法改进对大吞吐数据的处理,效果很好。
用户态驱动:在这种工作方式下,既规避了不必要的内存拷贝又避免了系统调用。 一个间接的影响在于,用户态驱动不受限于内核现有的数据格式和行为定义。 对mbuf头格式的重定义、对网卡DMA操作的重新优化可以获得更好的性能。 而用户态驱动也便于快速地迭代优化,甚至对不同场景进行不同的优化组合。
亲和性与独占:DPDK工作在用户态,线程的调度仍然依赖内核。利用线程的CPU亲和绑定的方式,特定任务可以被指定只在某个核上工作。 好处是可避免线程在不同核间频繁切换,核间线程切换容易导致因cache miss和cache write back造成的大量性能损失。 如果更进一步地限定某些核不参与Linux系统调度,就可能使线程独占该核,保证更多cache hit的同时,也避免了同一个核内的多任务切换开销。
降低访存开销:网络数据包处理是一种典型的I/O密集型(I/O bound)工作负载。 无论是CPU指令还是DMA,对于内存子系统(Cache+DRAM)都会访问频繁。 利用一些已知的高效方法来减少访存的开销能够有效地提升性能。 比如利用内存大页能有效降低TLB miss,比如利用内存多通道的交错访问能有效提高内存访问的有效带宽,再比如利用对于内存非对称性的感知可以避免额外的访存延迟。 而cache更是几乎所有优化的核心地带,这些有意思而且对性能有直接影响的部分。
DPDK采用了轮询或者轮询混杂中断的模式来进行收包和发包,此前主流运行在操作系统内核态的网卡驱动程序基本都是基于异步中断处理模式。
异步中断模式
当有包进入网卡收包队列后,网卡会产生硬件(MSIX/MSI/INTX)中断,进而触发CPU中断,进入中断服务程序,在中断服务程序(包含下半部)来完成收包的处理。当然为了改善包处理性能,也可以在中断处理过程中加入轮询,来避免过多的中断响应次数。总体而言,基于异步中断信号模式的收包,是不断地在做中断处理,上下文切换,每次处理这种开销是固定的,累加带来的负荷显而易见。在CPU比I/O速率高很多时,这个负荷可以被相对忽略,问题不大,但如果连接的是高速网卡且I/O频繁,大量数据进出系统,开销累加就被充分放大。中断是异步方式,因此CPU无需阻塞等待,有效利用率较高,特别是在收包吞吐率比较低或者没有包进入收包队列的时候, CPU可以用于其他任务处理。
当有包需要发送出去的时候,基于异步中断信号的驱动程序会准备好要发送的包,配置好发送队列的各个描述符。在包被真正发送完成时,网卡同样会产生硬件中断信号,进而触发CPU中断,进入中断服务程序,来完成发包后的处理,例如释放缓存等。与收包一样,发送过程也会包含不断地做中断处理,上下文切换,每次中断都带来CPU开销;同上,CPU有效利用率高,特别是在发包吞吐率比较低或者完全没有发包的情况。
轮询模式
DPDK起初的纯轮询模式是指收发包完全不使用任何中断,集中所有运算资源用于报文处理。但这不是意味着DPDK不可以支持任何中断。根据应用场景需要,中断可以被支持,最典型的就是链路层状态发生变化的中断触发与处理。
https://blog.csdn.net/jiechuhoudeshang/article/details/89213197?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168188310916782425180014%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=168188310916782425180014&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-17-89213197-null-null.142v84control_2,239v2insert_chatgpt&utm_term=%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BADPDK&spm=1018.2226.3001.4187