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