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