您好,登錄后才能下訂單哦!
這篇文章主要介紹“什么是DPDK”,在日常操作中,相信很多人在什么是DPDK問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”什么是DPDK”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
從我們用戶(hù)的使用就可以感受到網(wǎng)速一直在提升,而網(wǎng)絡(luò)技術(shù)的發(fā)展也從1GE/10GE/25GE/40GE/100GE的演變,從中可以得出單機(jī)的網(wǎng)絡(luò)IO能力必須跟上時(shí)代的發(fā)展。
1. 傳統(tǒng)的電信領(lǐng)域
IP層及以下,例如路由器、交換機(jī)、防火墻、基站等設(shè)備都是采用硬件解決方案?;趯?zhuān)用網(wǎng)絡(luò)處理器(NP),有基于FPGA,更有基于ASIC的。但是基于硬件的劣勢(shì)非常明顯,發(fā)生Bug不易修復(fù),不易調(diào)試維護(hù),并且網(wǎng)絡(luò)技術(shù)一直在發(fā)展,例如2G/3G/4G/5G等移動(dòng)技術(shù)的革新,這些屬于業(yè)務(wù)的邏輯基于硬件實(shí)現(xiàn)太痛苦,不能快速迭代。傳統(tǒng)領(lǐng)域面臨的挑戰(zhàn)是急需一套軟件架構(gòu)的高性能網(wǎng)絡(luò)IO開(kāi)發(fā)框架。
2. 云的發(fā)展
私有云的出現(xiàn)通過(guò)網(wǎng)絡(luò)功能虛擬化(NFV)共享硬件成為趨勢(shì),NFV的定義是通過(guò)標(biāo)準(zhǔn)的服務(wù)器、標(biāo)準(zhǔn)交換機(jī)實(shí)現(xiàn)各種傳統(tǒng)的或新的網(wǎng)絡(luò)功能。急需一套基于常用系統(tǒng)和標(biāo)準(zhǔn)服務(wù)器的高性能網(wǎng)絡(luò)IO開(kāi)發(fā)框架。
3. 單機(jī)性能的飆升
網(wǎng)卡從1G到100G的發(fā)展,CPU從單核到多核到多CPU的發(fā)展,服務(wù)器的單機(jī)能力通過(guò)橫行擴(kuò)展達(dá)到新的高點(diǎn)。但是軟件開(kāi)發(fā)卻無(wú)法跟上節(jié)奏,單機(jī)處理能力沒(méi)能和硬件門(mén)當(dāng)戶(hù)對(duì),如何開(kāi)發(fā)出與時(shí)并進(jìn)高吞吐量的服務(wù),單機(jī)百萬(wàn)千萬(wàn)并發(fā)能力。即使有業(yè)務(wù)對(duì)QPS要求不高,主要是CPU密集型,但是現(xiàn)在大數(shù)據(jù)分析、人工智能等應(yīng)用都需要在分布式服務(wù)器之間傳輸大量數(shù)據(jù)完成作業(yè)。這點(diǎn)應(yīng)該是我們互聯(lián)網(wǎng)后臺(tái)開(kāi)發(fā)最應(yīng)關(guān)注,也最關(guān)聯(lián)的。
想了解更多的小伙伴歡迎進(jìn)群973961276來(lái)一起交流學(xué)習(xí),更有海量學(xué)習(xí)資料跟大廠面試經(jīng)驗(yàn)分享。
在數(shù)年前曾經(jīng)寫(xiě)過(guò)《網(wǎng)卡工作原理及高并發(fā)下的調(diào)優(yōu)》一文,描述了Linux的收發(fā)報(bào)文流程。根據(jù)經(jīng)驗(yàn),在C1(8核)上跑應(yīng)用每1W包處理需要消耗1%軟中斷CPU,這意味著單機(jī)的上限是100萬(wàn)PPS(Packet Per Second)。從TGW(Netfilter版)的性能100萬(wàn)PPS,AliLVS優(yōu)化了也只到150萬(wàn)PPS,并且他們使用的服務(wù)器的配置還是比較好的。假設(shè),我們要跑滿(mǎn)10GE網(wǎng)卡,每個(gè)包64字節(jié),這就需要2000萬(wàn)PPS(注:以太網(wǎng)萬(wàn)兆網(wǎng)卡速度上限是1488萬(wàn)PPS,因?yàn)樽钚笮?4B《Bandwidth, Packets Per Second, and Other Network Performance Metrics》),100G是2億PPS,即每個(gè)包的處理耗時(shí)不能超過(guò)50納秒。而一次Cache Miss,不管是TLB、數(shù)據(jù)Cache、指令Cache發(fā)生Miss,回內(nèi)存讀取大約65納秒,NUMA體系下跨Node通訊大約40納秒。所以,即使不加上業(yè)務(wù)邏輯,即使純收發(fā)包都如此艱難。我們要控制Cache的命中率,我們要了解計(jì)算機(jī)體系結(jié)構(gòu),不能發(fā)生跨Node通訊。
從這些數(shù)據(jù),我希望可以直接感受一下這里的挑戰(zhàn)有多大,理想和現(xiàn)實(shí),我們需要從中平衡。問(wèn)題都有這些
1.傳統(tǒng)的收發(fā)報(bào)文方式都必須采用硬中斷來(lái)做通訊,每次硬中斷大約消耗100微秒,這還不算因?yàn)榻K止上下文所帶來(lái)的Cache Miss。
2.數(shù)據(jù)必須從內(nèi)核態(tài)用戶(hù)態(tài)之間切換拷貝帶來(lái)大量CPU消耗,全局鎖競(jìng)爭(zhēng)。
3.收發(fā)包都有系統(tǒng)調(diào)用的開(kāi)銷(xiāo)。
4.內(nèi)核工作在多核上,為可全局一致,即使采用Lock Free,也避免不了鎖總線、內(nèi)存屏障帶來(lái)的性能損耗。
5.從網(wǎng)卡到業(yè)務(wù)進(jìn)程,經(jīng)過(guò)的路徑太長(zhǎng),有些其實(shí)未必要的,例如netfilter框架,這些都帶來(lái)一定的消耗,而且容易Cache Miss。
從前面的分析可以得知IO實(shí)現(xiàn)的方式、內(nèi)核的瓶頸,以及數(shù)據(jù)流過(guò)內(nèi)核存在不可控因素,這些都是在內(nèi)核中實(shí)現(xiàn),內(nèi)核是導(dǎo)致瓶頸的原因所在,要解決問(wèn)題需要繞過(guò)內(nèi)核。所以主流解決方案都是旁路網(wǎng)卡IO,繞過(guò)內(nèi)核直接在用戶(hù)態(tài)收發(fā)包來(lái)解決內(nèi)核的瓶頸。
Linux社區(qū)也提供了旁路機(jī)制Netmap,官方數(shù)據(jù)10G網(wǎng)卡1400萬(wàn)PPS,但是Netmap沒(méi)廣泛使用。其原因有幾個(gè):
1.Netmap需要驅(qū)動(dòng)的支持,即需要網(wǎng)卡廠商認(rèn)可這個(gè)方案。
2.Netmap仍然依賴(lài)中斷通知機(jī)制,沒(méi)完全解決瓶頸。
3.Netmap更像是幾個(gè)系統(tǒng)調(diào)用,實(shí)現(xiàn)用戶(hù)態(tài)直接收發(fā)包,功能太過(guò)原始,沒(méi)形成依賴(lài)的網(wǎng)絡(luò)開(kāi)發(fā)框架,社區(qū)不完善。
那么,我們來(lái)看看發(fā)展了十幾年的DPDK,從Intel主導(dǎo)開(kāi)發(fā),到華為、思科、AWS等大廠商的加入,核心玩家都在該圈子里,擁有完善的社區(qū),生態(tài)形成閉環(huán)。早期,主要是傳統(tǒng)電信領(lǐng)域3層以下的應(yīng)用,如華為、中國(guó)電信、中國(guó)移動(dòng)都是其早期使用者,交換機(jī)、路由器、網(wǎng)關(guān)是主要應(yīng)用場(chǎng)景。但是,隨著上層業(yè)務(wù)的需求以及DPDK的完善,在更高的應(yīng)用也在逐步出現(xiàn)。
DPDK旁路原理:
圖片引自Jingjing Wu的文檔《Flow Bifurcation on Intel? Ethernet Controller X710/XL710》
左邊是原來(lái)的方式數(shù)據(jù)從 網(wǎng)卡 -> 驅(qū)動(dòng) -> 協(xié)議棧 -> Socket接口 -> 業(yè)務(wù)
右邊是DPDK的方式,基于UIO(Userspace I/O)旁路數(shù)據(jù)。數(shù)據(jù)從 網(wǎng)卡 -> DPDK輪詢(xún)模式-> DPDK基礎(chǔ)庫(kù) -> 業(yè)務(wù)
用戶(hù)態(tài)的好處是易用開(kāi)發(fā)和維護(hù),靈活性好。并且Crash也不影響內(nèi)核運(yùn)行,魯棒性強(qiáng)。
DPDK支持的CPU體系架構(gòu):x86、ARM、PowerPC(PPC)
DPDK支持的網(wǎng)卡列表:https://core.dpdk.org/supported/,我們主流使用Intel 82599(光口)、Intel x540(電口)
為了讓驅(qū)動(dòng)運(yùn)行在用戶(hù)態(tài),Linux提供UIO機(jī)制。使用UIO可以通過(guò)read感知中斷,通過(guò)mmap實(shí)現(xiàn)和網(wǎng)卡的通訊。
UIO原理:
要開(kāi)發(fā)用戶(hù)態(tài)驅(qū)動(dòng)有幾個(gè)步驟:
1.開(kāi)發(fā)運(yùn)行在內(nèi)核的UIO模塊,因?yàn)橛仓袛嘀荒茉趦?nèi)核處理
2.通過(guò)/dev/uioX讀取中斷
3.通過(guò)mmap和外設(shè)共享內(nèi)存
DPDK的UIO驅(qū)動(dòng)屏蔽了硬件發(fā)出中斷,然后在用戶(hù)態(tài)采用主動(dòng)輪詢(xún)的方式,這種模式被稱(chēng)為PMD(Poll Mode Driver)。
UIO旁路了內(nèi)核,主動(dòng)輪詢(xún)?nèi)サ粲仓袛?,DPDK從而可以在用戶(hù)態(tài)做收發(fā)包處理。帶來(lái)Zero Copy、無(wú)系統(tǒng)調(diào)用的好處,同步處理減少上下文切換帶來(lái)的Cache Miss。
運(yùn)行在PMD的Core會(huì)處于用戶(hù)態(tài)CPU100%的狀態(tài)
網(wǎng)絡(luò)空閑時(shí)CPU長(zhǎng)期空轉(zhuǎn),會(huì)帶來(lái)能耗問(wèn)題。所以,DPDK推出Interrupt DPDK模式。
Interrupt DPDK:
圖片引自David Su/Yunhong Jiang/Wei Wang的文檔《Towards Low Latency Interrupt Mode DPDK》
它的原理和NAPI很像,就是沒(méi)包可處理時(shí)進(jìn)入睡眠,改為中斷通知。并且可以和其他進(jìn)程共享同個(gè)CPU Core,但是DPDK進(jìn)程會(huì)有更高調(diào)度優(yōu)先級(jí)。
六、DPDK的高性能代碼實(shí)現(xiàn)
1. 采用HugePage減少TLB Miss
默認(rèn)下Linux采用4KB為一頁(yè),頁(yè)越小內(nèi)存越大,頁(yè)表的開(kāi)銷(xiāo)越大,頁(yè)表的內(nèi)存占用也越大。CPU有TLB(Translation Lookaside Buffer)成本高所以一般就只能存放幾百到上千個(gè)頁(yè)表項(xiàng)。如果進(jìn)程要使用64G內(nèi)存,則64G/4KB=16000000(一千六百萬(wàn))頁(yè),每頁(yè)在頁(yè)表項(xiàng)中占用16000000 * 4B=62MB。如果用HugePage采用2MB作為一頁(yè),只需64G/2MB=2000,數(shù)量不在同個(gè)級(jí)別。
而DPDK采用HugePage,在x86-64下支持2MB、1GB的頁(yè)大小,幾何級(jí)的降低了頁(yè)表項(xiàng)的大小,從而減少TLB-Miss。并提供了內(nèi)存池(Mempool)、MBuf、無(wú)鎖環(huán)(Ring)、Bitmap等基礎(chǔ)庫(kù)。根據(jù)我們的實(shí)踐,在數(shù)據(jù)平面(Data Plane)頻繁的內(nèi)存分配釋放,必須使用內(nèi)存池,不能直接使用rte_malloc,DPDK的內(nèi)存分配實(shí)現(xiàn)非常簡(jiǎn)陋,不如ptmalloc。
2. SNA(Shared-nothing Architecture)
軟件架構(gòu)去中心化,盡量避免全局共享,帶來(lái)全局競(jìng)爭(zhēng),失去橫向擴(kuò)展的能力。NUMA體系下不跨Node遠(yuǎn)程使用內(nèi)存。
3. SIMD(Single Instruction Multiple Data)
從最早的mmx/sse到最新的avx2,SIMD的能力一直在增強(qiáng)。DPDK采用批量同時(shí)處理多個(gè)包,再用向量編程,一個(gè)周期內(nèi)對(duì)所有包進(jìn)行處理。比如,memcpy就使用SIMD來(lái)提高速度。
SIMD在游戲后臺(tái)比較常見(jiàn),但是其他業(yè)務(wù)如果有類(lèi)似批量處理的場(chǎng)景,要提高性能,也可看看能否滿(mǎn)足。
4. 不使用慢速API
這里需要重新定義一下慢速API,比如說(shuō)gettimeofday,雖然在64位下通過(guò)vDSO已經(jīng)不需要陷入內(nèi)核態(tài),只是一個(gè)純內(nèi)存訪問(wèn),每秒也能達(dá)到幾千萬(wàn)的級(jí)別。但是,不要忘記了我們?cè)?0GE下,每秒的處理能力就要達(dá)到幾千萬(wàn)。所以即使是gettimeofday也屬于慢速API。DPDK提供Cycles接口,例如rte_get_tsc_cycles接口,基于HPET或TSC實(shí)現(xiàn)。
在x86-64下使用RDTSC指令,直接從寄存器讀取,需要輸入2個(gè)參數(shù),比較常見(jiàn)的實(shí)現(xiàn):
static inline uint64_t rte_rdtsc(void) { uint32_t lo, hi; __asm__ __volatile__ ( "rdtsc" : "=a"(lo), "=d"(hi) ); return ((unsigned long long)lo) | (((unsigned long long)hi) << 32); }
這么寫(xiě)邏輯沒(méi)錯(cuò),但是還不夠極致,還涉及到2次位運(yùn)算才能得到結(jié)果,我們看看DPDK是怎么實(shí)現(xiàn):
static inline uint64_t rte_rdtsc(void) { union { uint64_t tsc_64; struct { uint32_t lo_32; uint32_t hi_32; }; } tsc; asm volatile("rdtsc" : "=a" (tsc.lo_32), "=d" (tsc.hi_32)); return tsc.tsc_64; }
巧妙的利用C的union共享內(nèi)存,直接賦值,減少了不必要的運(yùn)算。但是使用tsc有些問(wèn)題需要面對(duì)和解決
CPU親和性,解決多核跳動(dòng)不精確的問(wèn)題
內(nèi)存屏障,解決亂序執(zhí)行不精確的問(wèn)題
禁止降頻和禁止Intel Turbo Boost,固定CPU頻率,解決頻率變化帶來(lái)的失準(zhǔn)問(wèn)題
5. 編譯執(zhí)行優(yōu)化
分支預(yù)測(cè)
現(xiàn)代CPU通過(guò)pipeline、superscalar提高并行處理能力,為了進(jìn)一步發(fā)揮并行能力會(huì)做分支預(yù)測(cè),提升CPU的并行能力。遇到分支時(shí)判斷可能進(jìn)入哪個(gè)分支,提前處理該分支的代碼,預(yù)先做指令讀取編碼讀取寄存器等,預(yù)測(cè)失敗則預(yù)處理全部丟棄。我們開(kāi)發(fā)業(yè)務(wù)有時(shí)候會(huì)非常清楚這個(gè)分支是true還是false,那就可以通過(guò)人工干預(yù)生成更緊湊的代碼提示CPU分支預(yù)測(cè)成功率。
#pragma once #if !__GLIBC_PREREQ(2, 3) # if !define __builtin_expect # define __builtin_expect(x, expected_value) (x) # endif #endif #if !defined(likely) #define likely(x) (__builtin_expect(!!(x), 1)) #endif #if !defined(unlikely) #define unlikely(x) (__builtin_expect(!!(x), 0)) #endif
CPU Cache預(yù)取
Cache Miss的代價(jià)非常高,回內(nèi)存讀需要65納秒,可以將即將訪問(wèn)的數(shù)據(jù)主動(dòng)推送的CPU Cache進(jìn)行優(yōu)化。比較典型的場(chǎng)景是鏈表的遍歷,鏈表的下一節(jié)點(diǎn)都是隨機(jī)內(nèi)存地址,所以CPU肯定是無(wú)法自動(dòng)預(yù)加載的。但是我們?cè)谔幚肀竟?jié)點(diǎn)時(shí),可以通過(guò)CPU指令將下一個(gè)節(jié)點(diǎn)推送到Cache里。
API文檔:https://doc.dpdk.org/api/rte__prefetch_8h.html
static inline void rte_prefetch0(const volatile void *p) { asm volatile ("prefetcht0 %[p]" : : [p] "m" (*(const volatile char *)p)); }
#if !defined(prefetch) #define prefetch(x) __builtin_prefetch(x) #endif
…等等
內(nèi)存對(duì)齊
內(nèi)存對(duì)齊有2個(gè)好處:
l 避免結(jié)構(gòu)體成員跨Cache Line,需2次讀取才能合并到寄存器中,降低性能。結(jié)構(gòu)體成員需從大到小排序和以及強(qiáng)制對(duì)齊。參考《Data alignment: Straighten up and fly right》
#define __rte_packed __attribute__((__packed__))
l 多線程場(chǎng)景下寫(xiě)產(chǎn)生False sharing,造成Cache Miss,結(jié)構(gòu)體按Cache Line對(duì)齊
#ifndef CACHE_LINE_SIZE #define CACHE_LINE_SIZE 64 #endif #ifndef aligined #define aligined(a) __attribute__((__aligned__(a))) #endif
常量?jī)?yōu)化
常量相關(guān)的運(yùn)算的編譯階段完成。比如C++11引入了constexp,比如可以使用GCC的__builtin_constant_p來(lái)判斷值是否常量,然后對(duì)常量進(jìn)行編譯時(shí)得出結(jié)果。舉例網(wǎng)絡(luò)序主機(jī)序轉(zhuǎn)換
#define rte_bswap32(x) ((uint32_t)(__builtin_constant_p(x) ? \ rte_constant_bswap32(x) : \ rte_arch_bswap32(x)))
其中rte_constant_bswap32的實(shí)現(xiàn)
#define RTE_STATIC_BSWAP32(v) \ ((((uint32_t)(v) & UINT32_C(0x000000ff)) << 24) | \ (((uint32_t)(v) & UINT32_C(0x0000ff00)) << 8) | \ (((uint32_t)(v) & UINT32_C(0x00ff0000)) >> 8) | \ (((uint32_t)(v) & UINT32_C(0xff000000)) >> 24))
5)使用CPU指令
現(xiàn)代CPU提供很多指令可直接完成常見(jiàn)功能,比如大小端轉(zhuǎn)換,x86有bswap指令直接支持了。
static inline uint64_t rte_arch_bswap64(uint64_t _x) { register uint64_t x = _x; asm volatile ("bswap %[x]" : [x] "+r" (x) ); return x; }
這個(gè)實(shí)現(xiàn),也是GLIBC的實(shí)現(xiàn),先常量?jī)?yōu)化、CPU指令優(yōu)化、最后才用裸代碼實(shí)現(xiàn)。畢竟都是頂端程序員,對(duì)語(yǔ)言、編譯器,對(duì)實(shí)現(xiàn)的追求不一樣,所以造輪子前一定要先了解好輪子。
Google開(kāi)源的cpu_features可以獲取當(dāng)前CPU支持什么特性,從而對(duì)特定CPU進(jìn)行執(zhí)行優(yōu)化。高性能編程永無(wú)止境,對(duì)硬件、內(nèi)核、編譯器、開(kāi)發(fā)語(yǔ)言的理解要深入且與時(shí)俱進(jìn)。
七、DPDK生態(tài)
對(duì)我們互聯(lián)網(wǎng)后臺(tái)開(kāi)發(fā)來(lái)說(shuō)DPDK框架本身提供的能力還是比較裸的,比如要使用DPDK就必須實(shí)現(xiàn)ARP、IP層這些基礎(chǔ)功能,有一定上手難度。如果要更高層的業(yè)務(wù)使用,還需要用戶(hù)態(tài)的傳輸協(xié)議支持。不建議直接使用DPDK。
目前生態(tài)完善,社區(qū)強(qiáng)大(一線大廠支持)的應(yīng)用層開(kāi)發(fā)項(xiàng)目是FD.io(The Fast Data Project),有思科開(kāi)源支持的VPP,比較完善的協(xié)議支持,ARP、VLAN、Multipath、IPv4/v6、MPLS等。用戶(hù)態(tài)傳輸協(xié)議UDP/TCP有TLDK。從項(xiàng)目定位到社區(qū)支持力度算比較靠譜的框架。
騰訊云開(kāi)源的F-Stack也值得關(guān)注一下,開(kāi)發(fā)更簡(jiǎn)單,直接提供了POSIX接口。
Seastar也很強(qiáng)大和靈活,內(nèi)核態(tài)和DPDK都隨意切換,也有自己的傳輸協(xié)議Seastar Native TCP/IP Stack支持,但是目前還未看到有大型項(xiàng)目在使用Seastar,可能需要填的坑比較多。
我們GBN Gateway項(xiàng)目需要支持L3/IP層接入做Wan網(wǎng)關(guān),單機(jī)20GE,基于DPDK開(kāi)發(fā)。
到此,關(guān)于“什么是DPDK”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。