1.前言
說來想學習DPDK已經是很久的事情了,奈何總是被所謂的緊急的事情耽誤,故而決心學習一下,記錄一下以便總結,暫時工作還沒完全用到, 但是DPDK總會成為一個大趨勢,借此學習一下前輩的設計思想,希望能有所啟發
2.DPDK介紹
Intel® DPDK 全稱 __Intel Data Plane Development Kit__,是intel提供的數據平面開發工具集,為Intel architecture(IA)處理器架構下用戶空間高效的數據包處理提供庫函數和驅動的支持,它不同於Linux系統以通用性設計為目的,而是專注於網絡應用中數據包的高性能處理。其工作在用戶層,取代傳統Linux系統中的網絡數據報文處理。但需要注意的是,DPDK提供的是高性能處理報文的能力,而不是對報文的處理。這也提供了我們自定義用戶協議棧的能力
3.DPDK 優勢
1)輪詢與中斷
起初的純輪詢模式是指收發包完全不使用任何中斷,集中所有運算資源用於報文處理。DPDK純輪詢模式是指收發包完全不使用中斷處理的高吞吐率的方 式。DPDK所有的收發包有關的中斷在物理端口初始化的時候都會關 閉,也就是說,CPU這邊在任何時候都不會收到收包或者發包成功的中 斷信號,也不需要任何收發包有關的中斷處理。具體收發包流程參見之后的文章單獨說明。網絡應用中可能存在的潮汐效應,在某些時間段網絡數據 流量可能很低,甚至完全沒有需要處理的包,這樣就會出現在高速端口 下低負荷運行的場景,而完全輪詢的方式會讓處理器一直全速運行,明 顯浪費處理能力和不節能。因此在DPDK R2.1和R2.2陸續添加了收包中 斷與輪詢的混合模式的支持,類似NAPI的思路,用戶可以根據實際應 用場景來選擇完全輪詢模式,或者混合中斷輪詢模式。而且,完全由用 戶來制定中斷和輪詢的切換策略,比如什么時候開始進入中斷休眠等待 收包,中斷喚醒后輪詢多長時間,等等。
2)多線程編程:
多線程編程早已不是什么新鮮的事物了,多線程的初衷是提高整體應用程序的性能,但是如果不加注意,就會將多線程的創建和銷毀開銷,鎖競爭,訪存沖突,cache失效,上下文切換等諸多消耗性能的因素引入進來。為了進一步提高性能,就必須仔細斟酌考慮線程在CPU不同核上的分布情況,這也就是常說的多核編程。多核編程和多線程有很大的不同:多線程是指每個CPU上可以運行多個線程,涉及到線程調度、鎖機制以及上下文的切換;而多核則是每個CPU核一個線程,核心之間訪問數據無需上鎖。為了最大限度減少線程調度的資源消耗,需要將Linux綁定在特定的核上,釋放其余核心來專供應用程序使用。DPDK的線程基於pthread接口創建,屬於搶占式線程模型,受內核 調度支配。DPDK通過在多核設備上創建多個線程,每個線程綁定到單 獨的核上,減少線程調度的開銷,以提高性能。DPDK的線程可以作為控制線程,也可以作為數據線程。在DPDK 的一些示例中,控制線程一般綁定到MASTER核上,接受用戶配置,並 傳遞配置參數給數據線程等;數據線程分布在不同核上處理數據包。同時還需要考慮CPU特性和系統是否支持NUMA架構,如果支持的話,不同插槽上CPU的進程要避免訪問遠端內存,盡量訪問本端內存。
3)CPU親核性:
當處理器進入多核架構后,自然會面對一個問題,按照什么策略將 任務線程分配到各個處理器上執行。眾所周知的是,這個分配工作一般 由操作系統完成。負載均衡當然是比較理想的策略,按需指定的方式也 是很自然的訴求,因為其具有確定性。簡單地說,CPU親和性(Core affinity)就是一個特定的任務要在某 個給定的CPU上盡量長時間地運行而不被遷移到其他處理器上的傾向 性。這意味着線程可以不在處理器之間頻繁遷移。這種狀態正是我們所 希望的,因為線程遷移的頻率小就意味着產生的負載小。將線程與CPU綁定,最直觀的好處就是提高了CPU Cache的命中 率,從而減少內存訪問損耗,提高程序的速度。在Linux內核中,所有的線程都有一個相關的數據結構,稱為 task_struct。這個結構非常重要,原因有很多;其中與親和性相關度最 高的是cpus_allowed位掩碼。這個位掩碼由n位組成,與系統中的n個邏 輯處理器一一對應。具有4個物理CPU的系統可以有4位。如果這些CPU 都啟用了超線程,那么這個系統就有一個8位的位掩碼。如果針對某個線程設置了指定的位,那么這個線程就可以在相關的 CPU上運行。因此,如果一個線程可以在任何CPU上運行,並且能夠根 據需要在處理器之間進行遷移,那么位掩碼就全是1。實際上,在Linux 中,這就是線程的默認狀態。DPDK通過把線程綁定到邏輯核的方法來避免跨核任務中的切換開 銷,但對於綁定運行的當前邏輯核,仍然可能會有線程切換的發生,若 希望進一步減少其他任務對於某個特定任務的影響,在親和的基礎上更 進一步,可以采取把邏輯核從內核調度系統剝離的方法。
4)大頁表:
默認下Linux采用4KB為一頁,頁越小內存越大,頁表的開銷越大,頁表的內存占用也越大。CPU有TLB(Translation Lookaside Buffer)成本高所以一般就只能存放幾百到上千個頁表項。如果進程要使用64G內存,則64G/4KB=16000000(一千六百萬)頁,每頁在頁表項中占用16000000 * 4B=62MB。如果用HugePage采用2MB作為一頁,只需64G/2MB=2000,數量不在同個級別。而DPDK采用HugePage,在x86-64下支持2MB、1GB的頁大小,幾何級的降低了頁表項的大小,從而減少TLB-Miss。
5)無鎖機制:
實際上DPDK內部也有讀寫鎖,LINUX系統本身也支持無鎖操作,並且DPDK內部的無鎖機制實現原理同LINUX系統提供的無鎖機制的實現原理類似。兩者都采用無鎖環形隊列的方式,采用環形隊列的好處是,當一個數據元素被用掉后,其余數據元素不需要移動其存儲位置,從而減少拷貝,提高效率。LINUX系統如果僅僅有一個讀用戶和一個寫用戶,那么不需要添加互斥保護機制就可以 保證數據的正確性。但是,如果有多個讀寫用戶訪問環形緩沖區,那么 必須添加互斥保護機制來確保多個用戶互斥訪問環形緩沖區。DPDK的無鎖環形隊列無論是單用戶讀寫還是多用戶讀寫都不需要使用互斥鎖保護。
5)cache預取:
處理器從一級Cache讀取數據需要3~5個時 鍾周期,二級是十幾個時鍾周期,三級是幾十個時鍾周期,而內存則需 要幾百個時鍾周期。DPDK必須保證所有需要讀取的數據都在Cache中,否則一旦出現Cache不命中,性能將會嚴重下降。為了保證這點,DPDK采用 了多種技術來進行優化,預取只是其中的一種
6)利用UIO技術:
為了讓驅動運行在用戶態,Linux提供UIO機制。使用UIO可以通過read感知中斷,通過mmap實現和網卡的通訊
4.數據包處理流程
1)Linux傳統方式處理數據包流程:
硬件中斷--->取包分發至內核線程--->軟件中斷--->內核線程在協議棧中處理包--->處理完畢通知用戶層
用戶層收包-->網絡層--->邏輯層--->業務層
2)DPDK處理數據包流程:
硬件中斷--->放棄中斷流程
用戶層通過設備映射取包--->進入用戶層協議棧--->邏輯層--->業務層
5.學習目標
理解DPDK的內存機制, 以及處理數據包的流程