一種面向云架構(gòu)的高性能網(wǎng)絡(luò)接口實(shí)現(xiàn)技術(shù)
掃描二維碼
隨時(shí)隨地手機(jī)看文章
0 概述
在傳統(tǒng)的電信IT產(chǎn)品中,高性能網(wǎng)絡(luò)接口一般采用特殊的硬件模塊來(lái)實(shí)現(xiàn),比如網(wǎng)絡(luò)處理器、ASIC、FPGA等等。這些特殊硬件模塊一般會(huì)采用特殊的架構(gòu)和指令集對(duì)網(wǎng)絡(luò)數(shù)據(jù)收發(fā)過(guò)程進(jìn)行優(yōu)化以達(dá)到更好的性能。然而,這也相應(yīng)使得開(kāi)發(fā)和維護(hù)這些模塊的成本非常的昂貴,同時(shí)還有一個(gè)無(wú)法解決的問(wèn)題是基于這些特殊硬件模塊實(shí)現(xiàn)的網(wǎng)絡(luò)接口不能移植到云中,因?yàn)樗鼈兏布鸟詈隙忍吡恕D柖傻某霈F(xiàn),使得通用處理器的性能得到了極大的提升,這也為基于通用處理器實(shí)現(xiàn)高性能網(wǎng)絡(luò)接口提供了可能,同時(shí)也為移植到云中提供了前提條件。
本文對(duì)基于通用X86架構(gòu)處理器和Linux下的傳統(tǒng)網(wǎng)絡(luò)接口實(shí)現(xiàn)模式進(jìn)行了分析,同時(shí)針對(duì)其不足提出了一種高性能網(wǎng)絡(luò)接口實(shí)現(xiàn)方案-HPNI。
1 傳統(tǒng)網(wǎng)絡(luò)接口實(shí)現(xiàn)分析
傳統(tǒng)網(wǎng)絡(luò)接口實(shí)現(xiàn)如圖2所示,Linux下傳統(tǒng)網(wǎng)絡(luò)接口處理流程一般包含以下幾個(gè)步驟:
(1)系統(tǒng)啟動(dòng)之后,內(nèi)核中的驅(qū)動(dòng)程序進(jìn)行相應(yīng)的資源分配以及網(wǎng)卡寄存器配置,比如分配數(shù)據(jù)包緩沖區(qū),使能DMA傳輸通道等等;
(2)網(wǎng)卡初始化完成以后,當(dāng)網(wǎng)卡從網(wǎng)絡(luò)收到數(shù)據(jù)包的時(shí)候,會(huì)將數(shù)據(jù)包通過(guò)DMA方式傳送到內(nèi)核中的數(shù)據(jù)包緩沖區(qū)中,并生成相應(yīng)的數(shù)據(jù)包描述符存放在環(huán)形隊(duì)列里面;
(3)網(wǎng)卡觸發(fā)硬中斷通知內(nèi)核,內(nèi)核在中斷處理程序中產(chǎn)生相應(yīng)軟中斷給應(yīng)用程序收包任務(wù);
(4)應(yīng)用程序收包任務(wù)通過(guò)系統(tǒng)調(diào)用收取數(shù)據(jù)包,數(shù)據(jù)包也將從內(nèi)核空間拷貝到用戶空間;
(5)收包任務(wù)通過(guò)共享隊(duì)列把數(shù)據(jù)包傳遞給處理任務(wù);
(6)處理任務(wù)通過(guò)共享隊(duì)列把處理好的數(shù)據(jù)包傳遞給發(fā)包任務(wù);
(7)發(fā)包任務(wù)通過(guò)系統(tǒng)調(diào)用把數(shù)據(jù)包傳遞給內(nèi)核,通過(guò)采用一次內(nèi)存拷貝實(shí)現(xiàn);
(8)驅(qū)動(dòng)程序根據(jù)存放在環(huán)形隊(duì)列里面的數(shù)據(jù)包描述符啟動(dòng)相應(yīng)的DMA傳輸任務(wù);
(9)數(shù)據(jù)包傳輸完成后,網(wǎng)卡觸發(fā)中斷通知內(nèi)核做相應(yīng)處理。
下面先對(duì)傳統(tǒng)網(wǎng)絡(luò)接口的性能關(guān)鍵點(diǎn)進(jìn)行分析。
1.1 中斷和系統(tǒng)調(diào)用
Linux下傳統(tǒng)網(wǎng)絡(luò)接口實(shí)現(xiàn)的一個(gè)關(guān)鍵因素是中斷技術(shù),網(wǎng)卡通過(guò)中斷與內(nèi)核保持同步。但中斷處理會(huì)引入很大的性能損失,因?yàn)楫?dāng)CPU處理中斷的時(shí)候,它必須儲(chǔ)存和恢復(fù)自己的狀態(tài),進(jìn)行上下文切換以及在進(jìn)入和退出中斷處理程序的時(shí)候可能引入緩存(cache)操作。在進(jìn)行大流量數(shù)據(jù)包處理的時(shí)候,由于CPU被頻繁地中斷,由此帶來(lái)的性能損失會(huì)非常嚴(yán)重。
當(dāng)使用Linux系統(tǒng)提供的標(biāo)準(zhǔn)socket接口來(lái)實(shí)現(xiàn)網(wǎng)絡(luò)通信時(shí),會(huì)觸發(fā)大量的系統(tǒng)調(diào)用,當(dāng)應(yīng)用程序通過(guò)socket系統(tǒng)調(diào)用進(jìn)行網(wǎng)絡(luò)通信時(shí),需要經(jīng)歷從用戶態(tài)到內(nèi)核態(tài)的切換以及其反向過(guò)程,在切換過(guò)程當(dāng)中需要進(jìn)行上下文的保存,比如對(duì)相關(guān)寄存器進(jìn)行堆棧壓棧操作,保存當(dāng)前指令指針等等。這些操作都會(huì)消耗系統(tǒng)資源,當(dāng)處理高速的數(shù)據(jù)流量時(shí),隨著系統(tǒng)調(diào)用數(shù)量的急劇增加而導(dǎo)致系統(tǒng)資源的大量消耗。
1.2 內(nèi)存相關(guān)性能問(wèn)題
1.2.1 內(nèi)存拷貝
在使用標(biāo)準(zhǔn)套接字進(jìn)行數(shù)據(jù)包收發(fā)時(shí),數(shù)據(jù)在應(yīng)用程序和內(nèi)核之間進(jìn)行傳遞必須通過(guò)內(nèi)存拷貝來(lái)完成,原因在于用戶空間的內(nèi)存和內(nèi)核空間的內(nèi)存是處在物理內(nèi)存不同的位置上。內(nèi)存拷貝是一個(gè)非常消耗資源的過(guò)程,當(dāng)需要收發(fā)的數(shù)據(jù)包流量很大時(shí),這種開(kāi)銷將會(huì)極大地影響系統(tǒng)的性能。
1. 2.2 內(nèi)存訪問(wèn)效率
在絕大多數(shù)情況下,應(yīng)用程序并不直接通過(guò)物理內(nèi)存地址來(lái)訪問(wèn)內(nèi)存,而是采用虛擬地址,當(dāng)CPU收到內(nèi)存訪問(wèn)指令時(shí)會(huì)先把虛擬地址轉(zhuǎn)換成實(shí)際的物理地址,然后進(jìn)行內(nèi)存的訪問(wèn)操作。這種方式已經(jīng)被普遍接受,甚至被稱作是IT時(shí)代最杰出的發(fā)明之一,但是這種非直接內(nèi)存訪問(wèn)方式并不是沒(méi)有代價(jià)的,地址的翻譯需要通過(guò)頁(yè)表來(lái)完成,頁(yè)表通常情況下是儲(chǔ)存在內(nèi)存當(dāng)中的,訪問(wèn)速度很慢,為了解決這個(gè)問(wèn)題,大部分系統(tǒng)都采用了TLB(Tralaslation Lookaside Buffer)的方式,最近觸發(fā)的一些地址翻譯結(jié)果都會(huì)保存在TLB中,TLB實(shí)際上使用的是CPU的緩存(cache),訪問(wèn)速度非常快,然而cache容量小,只有最近訪問(wèn)的一部分頁(yè)表項(xiàng)能保存下來(lái),因此出現(xiàn)了“TLB Miss”;當(dāng)CPU發(fā)現(xiàn)當(dāng)前虛擬地址無(wú)法在TLB里面找到相對(duì)應(yīng)的表項(xiàng)時(shí),就引入了一個(gè)TLB Miss,此時(shí)CPU需要回到內(nèi)存當(dāng)中的頁(yè)表進(jìn)行查找,性能會(huì)顯著降低。因此當(dāng)程序需要進(jìn)行頻繁的內(nèi)存操作時(shí),需要盡量減少TLBMiss的次數(shù)。當(dāng)前系統(tǒng)定義的頁(yè)面大小一般是4k字節(jié),當(dāng)應(yīng)用程序使用比如2G這樣的大內(nèi)存時(shí),總共需要50多萬(wàn)個(gè)頁(yè)表項(xiàng),這個(gè)數(shù)目是相當(dāng)龐大的,同時(shí)因?yàn)橹挥幸恍〔糠值谋眄?xiàng)能夠裝載在TLB中,因此TLB Miss的幾率也很大。另外,一般情況下程序的虛擬內(nèi)存空間都是連續(xù)的,但其對(duì)應(yīng)的物理內(nèi)存空間卻不一定是連續(xù)的,這樣會(huì)導(dǎo)致一次虛擬內(nèi)存尋址操作可能需要進(jìn)行多次物理內(nèi)存尋址操作才能完成,這也會(huì)成倍地增加內(nèi)存訪問(wèn)消耗的時(shí)間。
1.3 多核親和力
多核系統(tǒng)對(duì)提高系統(tǒng)的性能有很大的幫助,當(dāng)前大部分系統(tǒng)的調(diào)度算法會(huì)把當(dāng)前的任務(wù)放到最空閑的核上執(zhí)行,這樣的好處是能夠增加CPU資源的利用率,但因?yàn)槊總€(gè)CPU核心都有自己獨(dú)立的寄存器和cache,當(dāng)任務(wù)從一個(gè)核心遷移到另一個(gè)核心時(shí),會(huì)引發(fā)大量的核問(wèn)切換開(kāi)銷,比如上下文切換,cache miss等等。另外,對(duì)于使用NUMA(Non-Uniform Memory Access)架構(gòu)的系統(tǒng)而言,核間切換的開(kāi)銷會(huì)更大,在SMP(Svmmetric Multiprocessing)架構(gòu)下,所有核心是通過(guò)共享接口訪問(wèn)內(nèi)存的,因此每個(gè)核心訪問(wèn)內(nèi)存的速度是一樣的,但在NUMA架構(gòu)下,核心對(duì)內(nèi)存的訪問(wèn)分為本地訪問(wèn)和遠(yuǎn)程訪問(wèn)。核心訪問(wèn)本地內(nèi)存的速度要比訪問(wèn)遠(yuǎn)端內(nèi)存的速度快很多,當(dāng)任務(wù)從核心A切換到核心B的時(shí)候,如果它仍然使用之前在A上分配的內(nèi)存,那么其內(nèi)存訪問(wèn)模式會(huì)從本地模式切換成遠(yuǎn)程模式,從而引起內(nèi)存訪問(wèn)速度的下降。
1.4 共享隊(duì)列的訪問(wèn)
當(dāng)把數(shù)據(jù)包從一個(gè)任務(wù)傳遞到另外一個(gè)任務(wù)的時(shí)候,需要用到共享隊(duì)列。通常情況下,在訪問(wèn)共享隊(duì)列的時(shí)候會(huì)用到Mutex鎖來(lái)保證訪問(wèn)的一致性。當(dāng)應(yīng)用程序申請(qǐng)Mutex鎖失敗之后會(huì)陷入內(nèi)核態(tài)中睡眠,當(dāng)鎖可用之后再?gòu)膬?nèi)核態(tài)切換到用戶態(tài)執(zhí)行,這里也引入了上下文切換的開(kāi)銷,而且當(dāng)數(shù)據(jù)流量很大的時(shí)候,相應(yīng)的開(kāi)銷也會(huì)非常大。為了消除這類開(kāi)銷,業(yè)界也提出了一些改進(jìn)的方法,比如自旋鎖(spinlock),自旋鎖一直在用戶態(tài)運(yùn)行,不會(huì)陷入內(nèi)核態(tài)中,因此也不會(huì)產(chǎn)生上下文切換的開(kāi)銷,但是它還是存在一些弊端:一方面可能造成死鎖,如果一個(gè)線程拿到鎖之后被意外銷毀,其它等待此鎖的線程會(huì)發(fā)生死鎖;另一方面,當(dāng)共享隊(duì)列和線程數(shù)量猛增時(shí),鎖的數(shù)量也會(huì)同時(shí)增加,對(duì)鎖的管理會(huì)給系統(tǒng)帶來(lái)很大的負(fù)擔(dān)。
2 HPNI實(shí)現(xiàn)原理
2.1 傳統(tǒng)網(wǎng)絡(luò)接口實(shí)現(xiàn)模式的不足
從上述分析可以得出傳統(tǒng)網(wǎng)絡(luò)接口的實(shí)現(xiàn)主要有以下幾點(diǎn)不足:
(1)上下文切換開(kāi)銷太多,這些開(kāi)銷主要是由中斷、系統(tǒng)調(diào)用、鎖以及核間切換引入;
(2)內(nèi)存拷貝的開(kāi)銷太多;
(3)內(nèi)存訪問(wèn)效率不高,缺乏相應(yīng)的優(yōu)化;
(4)采用帶鎖共享隊(duì)列進(jìn)行數(shù)據(jù)共享,引入額外開(kāi)銷;
(5)收發(fā)包操作必須經(jīng)過(guò)Linux內(nèi)核單線程完成,無(wú)法擴(kuò)展成多核多線程模式從而提高性能。
2. 2 HPNI的原理
針對(duì)上述不足,提出了一種新型的網(wǎng)絡(luò)接口實(shí)現(xiàn)模式,如圖3所示。
HPNI主要包括以下幾項(xiàng)關(guān)鍵技術(shù):
(1)通過(guò)Linux提供的UIO框架,實(shí)現(xiàn)了網(wǎng)卡用戶空間驅(qū)動(dòng)程序,UIO能夠把網(wǎng)卡設(shè)備內(nèi)存空間通過(guò)文件系統(tǒng)的方式傳遞給用戶空間,比如dev/uioXX,因此用戶空間程序能夠讀取到設(shè)備地址段并映射到用戶空間內(nèi)存中,比如通過(guò)mmap()。通過(guò)上述方式可以在用戶空間程序中完成驅(qū)動(dòng)程序的功能。這種方法的優(yōu)點(diǎn)是去掉了內(nèi)存拷貝,同時(shí)因?yàn)樗泄ぷ鞫荚谟脩艨臻g完成,也節(jié)省了系統(tǒng)調(diào)用的開(kāi)銷。
(2)關(guān)掉網(wǎng)卡中斷,驅(qū)動(dòng)程序采用輪詢方式,消除中斷引起的開(kāi)銷。
(3)用戶空間的數(shù)據(jù)包緩沖區(qū)采用huge page分配的連續(xù)物理內(nèi)存區(qū),通過(guò)LinuX提供的huge page接口能夠分配大于4k的頁(yè),從而減少頁(yè)表的大小,降低TLB Miss發(fā)生的概率。另外連續(xù)的物理內(nèi)存塊也能減少地址轉(zhuǎn)換引起的查表次數(shù),進(jìn)一步提高性能。
(4)任務(wù)線程和CPU核心之間采用靜態(tài)綁定,比如接收包線程綁定1核,處理包線程綁定2核,發(fā)送包線程綁定3核,從而消除核間切換產(chǎn)生的開(kāi)銷。
另外,對(duì)于NUMA架構(gòu)的CPU,每個(gè)任務(wù)都使用本地內(nèi)存,進(jìn)一步提高內(nèi)存訪問(wèn)速度。
(5)通過(guò)CAS(Compare And Swap)原子操作,多個(gè)任務(wù)可以在不加鎖的情況下對(duì)共享隊(duì)列進(jìn)行訪問(wèn),增加和刪除節(jié)點(diǎn)。在X86架構(gòu)下CAS是通過(guò)CMPXCHG指令實(shí)現(xiàn)的,該指令的作用就是把一個(gè)指針指向內(nèi)存的值同一個(gè)給定的值進(jìn)行比較,如果相等,就對(duì)對(duì)應(yīng)內(nèi)存賦一個(gè)新的值,否則不做任何操作。通過(guò)上述方法可以實(shí)現(xiàn)一種沖突檢測(cè)機(jī)制,當(dāng)任務(wù)發(fā)現(xiàn)該隊(duì)列己經(jīng)被訪問(wèn)時(shí),主動(dòng)等待直到隊(duì)列空閑。無(wú)鎖隊(duì)列消除了加鎖引起的開(kāi)銷,同時(shí)也能避免死鎖的情況。
(6)基于網(wǎng)卡RSS(Receive-side Scaling)功能可以平滑擴(kuò)展成多任務(wù)模式,RSS功能可以將收到的數(shù)據(jù)包基于五元組做哈希運(yùn)算,從而分發(fā)到不同的隊(duì)列當(dāng)中進(jìn)行并行處理,每一個(gè)隊(duì)列可以對(duì)應(yīng)一個(gè)收包任務(wù),從而成倍地提高處理性能。
3 對(duì)比實(shí)驗(yàn)及結(jié)果分析
3. 1 實(shí)驗(yàn)一
實(shí)驗(yàn)環(huán)境描述如下:一臺(tái)數(shù)據(jù)包發(fā)生器,最大可產(chǎn)生流量為80Mpps的64字節(jié)的數(shù)據(jù)包。一臺(tái)服務(wù)器配置Intel的Sandy Bridge 8核處理器,每個(gè)核心2.0GHZ。操作系統(tǒng)采用RedHat Enterprise Linux 6.2。網(wǎng)卡采用Intel 82599 10G以太網(wǎng)控制器。運(yùn)行的軟件包含三個(gè)線程,一個(gè)收包線程,一個(gè)轉(zhuǎn)發(fā)線程,一個(gè)發(fā)送線程。傳統(tǒng)網(wǎng)絡(luò)實(shí)現(xiàn)方式下采用了RAWSocket方式直接收發(fā)處理層二數(shù)據(jù)包,如圖4所示。
實(shí)驗(yàn)結(jié)果如圖5所示,可以得出傳統(tǒng)網(wǎng)絡(luò)接口實(shí)現(xiàn)模式下性能的峰值在180Kpps左右,而且隨著網(wǎng)絡(luò)數(shù)據(jù)流量的增大,性能呈現(xiàn)下降趨勢(shì),主要因?yàn)殡S著網(wǎng)絡(luò)流量的增加,額外的系統(tǒng)開(kāi)銷也在不斷增加。HPNI模式下性能峰值在1.8Mpps左右,而且隨著網(wǎng)絡(luò)流量的增加,性能比較穩(wěn)定,抗沖擊力比較強(qiáng)。
3.2 實(shí)驗(yàn)二
采用與實(shí)驗(yàn)一相同的硬件環(huán)境,同時(shí)開(kāi)啟多個(gè)相同的任務(wù)線程,每個(gè)線程在一個(gè)任務(wù)循環(huán)內(nèi)完成收包、改包、發(fā)包的工作,比較兩種接口模式在多核多任務(wù)配置下的性能。另外,在HPNI模式下同時(shí)使能網(wǎng)卡的RSS功能,生成多個(gè)隊(duì)列分別對(duì)應(yīng)每個(gè)任務(wù)線程,每個(gè)任務(wù)線程靜態(tài)綁定一個(gè)CPU核心,如圖6所示。
實(shí)驗(yàn)結(jié)果如圖7所示,在傳統(tǒng)網(wǎng)絡(luò)接口實(shí)現(xiàn)模式下,因?yàn)槭芟抻贚inux內(nèi)核處理的瓶頸,即使采用了多線程并發(fā),其性能峰值仍然處于180Kpps左右。HPNI卻能很好地利用多線程的并發(fā),在網(wǎng)卡RSS功能的配合之下性能得到成倍的提高。也可以看到多核下面HPNI的性能并不是一直隨著核數(shù)的增加而線性增加的,主要因?yàn)镃PU內(nèi)的核心之間并不是完全獨(dú)立的,它們之間也存在一些共享資源的競(jìng)爭(zhēng),比如總線的訪問(wèn),從而對(duì)性能產(chǎn)生一些負(fù)面的影響。
4 結(jié)語(yǔ)
本文分析了傳統(tǒng)Linux下網(wǎng)絡(luò)接口實(shí)現(xiàn)的性能瓶頸,針對(duì)其不足提出了一種新型的網(wǎng)絡(luò)接口實(shí)現(xiàn)模式。實(shí)驗(yàn)結(jié)果表明,HPNI可以達(dá)到12Mpps的包轉(zhuǎn)發(fā)速率,完全可以勝任核心路由網(wǎng)絡(luò)以外網(wǎng)絡(luò)聚合點(diǎn)的工作,比如小型企業(yè)網(wǎng)關(guān)等。另外,因?yàn)镠PNI的容量可以動(dòng)態(tài)調(diào)整,因此可以以較高的性價(jià)比實(shí)現(xiàn)各種性能要求的網(wǎng)絡(luò)轉(zhuǎn)發(fā)節(jié)點(diǎn)?;谕ㄓ锰幚砥骱蜆?biāo)準(zhǔn)操作系統(tǒng)的特性,也使得HPNI能夠快速地部署到SDN中。HPNI既可以直接部署在IT server上,也可以部署在虛擬機(jī)當(dāng)中,從而實(shí)現(xiàn)高速NFV的功能。當(dāng)然,HPNI也存在一點(diǎn)不足,因?yàn)椴捎昧溯喸兡J?,雖然保證了數(shù)據(jù)處理的實(shí)時(shí)性,但也導(dǎo)致了較大的CPU負(fù)載,當(dāng)網(wǎng)絡(luò)流量很低的時(shí)候,系統(tǒng)資源利用率不是很高。后續(xù)可以針對(duì)此點(diǎn)做一些優(yōu)化,比如結(jié)合機(jī)器學(xué)習(xí)算法對(duì)輸入數(shù)據(jù)流量進(jìn)行預(yù)測(cè),當(dāng)輸入流量降低時(shí)通過(guò)CPU提供的pause指令降低CPU負(fù)載,從而降低系統(tǒng)資源的使用。