DPDK QoS之分層調度器

原創翻譯,轉載請註明出處。前端

 

分層調度器的時機主要體如今TX側,正好在傳遞報文以前。它的主要目的是在每一個網絡節點按照服務級別協議來對不一樣的流量分類和對不一樣的用戶的報文區分優先級並排序。

1、概述
分層調度器跟之前使用網絡處理器實現的每條流或一組流的報文隊列和調度的流量管理器很類似。它看起來像在傳輸以前的一個臨時存儲了很大數量報文的緩衝區(入隊操做)。當網卡TX請求更多報文去發送的時候,這些報文遞交給網卡TX的預約義的SLA的報文選擇邏輯模塊以後會刪除。(出隊操做)。



分層調度器對大數量的報文隊列作了優化。當只須要小數量的隊列時,會使用消息傳遞隊列來替代。更多詳情參考"Worst Case Scenarios for Performance"。

2、分層調度
以下圖:


分層的第一級是 Ethernet TX 1/10/40端口,以後的分級是子端口,流水線,流分類和隊列。
有表明性的是,每個子端口表示一個預約義好的用戶組,而每個流水線表示一個我的用戶。每個流分類表示不一樣的流量類型,流量類型包含了具體的丟包率,時延,抖動等需求,好比語音,視頻或數據傳輸。每個隊列從一到多個相同用戶相同類型的鏈接裏接待(原文是動詞:host)報文。

下面的表格對每一個分層作了功能描述:
#   級別             兄弟                      功能描述
1   Port              0                         一、以太端口1/10/40 GbE輸出; 二、多個端口具備相同的優先級,RR調度
2   Subport           可配置,默認8個           一、使用令牌桶算法流量整形(每一個子端口一個令牌桶) 二、每一個流分類在子端口級別上有強制上限。  三、當高優先級不使用時,低優先級的流分類能夠重用子端口的帶寬
3   Pipe              可配置,默認4K            一、使用令牌桶算法流量整形,每一個流水線一個令牌桶
4   Traffic Class     4                         一、同一個流水線的流分類按嚴格優先級順序處理 二、在流水線級別每一個流分類有強制的上限  三、當高優先級不使用時,低優先級的流分類能夠重用流水線的帶寬 四、當子端口流分類超額訂購以後(配置形成的),流水線的流分類上限是一個動態調整的值。並共享給全部子端口流水線
5  queue              4                         一、同一個流分類裏的隊列按照預約義的權重按WRR調度ios

 

3、API
1.端口調度配置API
rte_sched.h裏包含了端口,子端口和流水線的配置函數。

2.端口調度器入隊API
int rte_sched_port_enqueue(struct rte_sched_port *port, struct rte_mbuf **pkts, uint32_t n_pkts)
               
3.端口調度器出隊API
int rte_sched_port_dequeue(struct rte_sched_port *port, struct rte_mbuf **pkts, uint32_t n_pkts)

4.使用舉例算法

 1 /* File "application.c" */
 2 #define N_PKTS_RX 64
 3 #define N_PKTS_TX 48
 4 #define NIC_RX_PORT 0
 5 #define NIC_RX_QUEUE 0
 6 #define NIC_TX_PORT 1
 7 #define NIC_TX_QUEUE 0
 8 struct rte_sched_port *port = NULL;
 9 struct rte_mbuf *pkts_rx[N_PKTS_RX], *pkts_tx[N_PKTS_TX];
10 uint32_t n_pkts_rx, n_pkts_tx;
11 /* Initialization */
12 <initialization code>
13 /* Runtime */
14 while (1) {
15     /* Read packets from NIC RX queue */
16     n_pkts_rx = rte_eth_rx_burst(NIC_RX_PORT, NIC_RX_QUEUE, pkts_rx, N_PKTS_RX);
17     /* Hierarchical scheduler enqueue */
18     rte_sched_port_enqueue(port, pkts_rx, n_pkts_rx);
19     /* Hierarchical scheduler dequeue */
20     rte_sched_port_enqueue(port, pkts_rx, n_pkts_rx);
21     /* Hierarchical scheduler dequeue */
22     n_pkts_tx = rte_sched_port_dequeue(port, pkts_tx, N_PKTS_TX);
23     /* Write packets to NIC TX queue */
24     rte_eth_tx_burst(NIC_TX_PORT, NIC_TX_QUEUE, pkts_tx, n_pkts_tx);
25 }

4.實現細節
每一個端口的內部數據結構,下面是原理解釋圖:數組

 

#   數據結構    大小(bytes)   #每一個端口    入隊    出隊    功能描述
1   子端口表項   64          #端口的子端口數   .     Rd,Wr    子端口的持久化數據(如積分,等等)
2   流水線表項   64          #端口的流水線數   .     Rd,Wr    流水線和它的流分類依據隊列(積分)(這些會在運行期間被更新)的持久化數據。流水線配置參數在運行期間不支持修改。相同流水線的配置參數會多個流水線共享,因此它們不是流水線表的一部分。
3   隊列表項     4           #端口的隊列數   Rd,Wr  Rd,Wr   隊列的持久化數據(好比讀寫指針)。全部隊列的每個流分類,都是同樣的隊列大小。任何一個流水線的流水線表項都是存在同一個cache line裏。

緩存

5.多核擴展策略
(1) 不一樣的物理端口運行不一樣的線程。同一個端口的入隊和出隊在同一個線程裏執行。
(2) 不一樣的線程使用同一個物理端口,經過分隔同一個物理端口(虛擬端口)的不一樣的子端口集合來運行。一樣,一個子端口也能分隔成多個子端口集合,來運行不一樣的線程,出隊和入隊都是在同一個端口的同一個線程。惟一的要求是,考慮到性能,不能在一個核裏處理所有的端口。

6.在同一個出端口入隊和出隊
在不一樣的CPU核上執行同一個出端口入隊和出隊的操做,會對調度器的性能有顯著影響,因此是不推薦這麼作。
端口的入隊和出隊操做由以下的數據結構來共享訪問:
(1)報文描述符
(2)隊列表
(3)隊列存儲區域
(4)活動隊列的位圖(bitmap)
能預料到的性能損耗是因爲:
(1)須要保證隊列和位圖操做是線程安全的,這就須要用鎖來保證原子訪問(好比自旋鎖/信號量)或者使用無鎖的原子訪問(好比:Test/Set, Compare And Swap(CAS)等等)。這比前面說的狀況影響更大。
(2)在2個CPU核的緩存結構(知足緩存一致性)裏,雙向(Ping-pong)地在高速緩存線(cache line)存放共享數據結構

所以,調度器的入隊和出隊操做必須在同一個線程裏執行,這樣隊列和位圖的操做就沒有線程安全的性能損耗以及能夠保存調度器數據結構在同一個CPU核上。

7.性能調優
增長網卡端口的數量僅僅只須要成比例的增長用來流量調度的CPU核的數量。

8.入隊流水線
每個報文的步驟順序是:
(1)mbuf裏數據字段的訪問要求識別出報文的目的隊列。這些字段包括:端口,子端口,流分類和流分類的隊列,這些都是分類階段設置的。
(2)訪問隊列數據結構要識別出寫操做在隊列數組中的位置。若是隊列是滿的,那麼這個報文會被丟棄。
(3)訪問隊列數組存儲報文的位置(好比:寫mbuf指針)
須要注意的是,這些步驟是有強相關的數據依賴的。好比,第2步和第3步不能在第1步和第2步的返回可用的結果以前啓動。這樣就阻止了CPU經過亂序執行來顯著提升性能的優化行爲。
考慮到很高速率的報文接收以及很大數量的隊列,能夠預料到在當前CPU,對當前報文入隊須要訪問的數據結構是不在L1,或者L2緩存的,所以會去內存中訪問,這樣會致使L1和L2數據緩存未命中(cache miss)。大量的L一、L2緩存未命中在性能上確定是不可接受的。
一個解決方案是經過預先讀取須要的數據結構。預取操做有一個執行延遲,數據結構在當前預取的狀態時,CPU是不能訪問它的,這個時候,CPU能夠去執行其餘的工做。其餘工做是去執行其餘報文的入隊順序不一樣階段的操做,所以就實現了入隊操做的流水線。
下圖闡述了流水線4個階段的入隊操做實現,每一個階段執行2個報文。沒有那個報文能夠在同一時間處於大於一個流水線階段。安全

 

擁塞管理方案經過隊列流水線來描述就很是簡單了:
報文入隊直到特定的隊列滿了,這時,全部的報文都只能到同一個丟包隊列,直到報文被消耗完(經過出隊操做),這裏能夠經過使能RED/WRED來改進隊列流水線,經過查看隊列的使用狀況和特定報文的報文優先級來決定出隊或丟棄。(這就與任意的讓全部報文都入隊/丟棄全部報文不一樣了。)

9.出隊狀態機
從當前流水線調度下一個報文的步驟順序是:
(1)使用bitmap掃描識別出下一個活動流水線,預取流水線。
(2)讀取流水線數據結構。更新當前流水線和它的子端口的積分。識別當前流水線的第一個活動流分類,經過WRR來選擇下一個隊列,預取當前流水線的16個隊列的隊列指針。
(3)從當前WRR隊列裏讀取下一個元素並預取它的報文描述符。
(4)從報文描述符(mbuf數據結構)裏讀取報文長度。基於報文長度和可用積分(如當前流水線,流水線流分類,子端口和子端口流分類),來執行或不執行調度。

爲了不緩存未命中,上述的數據結構(流水線,隊列,隊列數組,mbufs)都會在訪問以前預取過來。隱藏預取操做的延遲方案是在當前流水線的預取指令發出以後當即從當前流水線(流水線 grinder A)切換到另一個流水線(grinder B)。這就給了足夠的時間在執行權切換回以前的流水線(grinder A)以前來完成預取操做。
出隊流水線狀態機利用數據在CPU高速緩存裏會提升性能的原理,所以,在從同一個流水線的活動流分類移動到另一個流水線以前,它會嘗試從一個流水線和流水線流分類裏發送儘量多的報文(直到最大的可用報文和積分)網絡

10.時鐘同步
出端口在調度器調度數據傳輸的時候就像在模仿一個有不少槽位的傳送帶裝置。對於10GbE,上面有12.5億個字節槽位須要端口調度器每秒去填充。若是調度器不可以快去填充,那麼就有足夠的報文和積分繼續存在,這樣那些槽位就不會被使用,也就浪費了帶寬。
原則上,分層調度器出隊操做是有網卡TX觸發的。一般,一旦網卡Tx輸入隊列的使用下降到了一個預設的閥值,端口調度器就會被喚醒(基於中斷或者基於輪詢,經過持續的監視隊列的使用率)來將更多的報文加入到隊列。

(1)內部時鐘參考源
爲了提高積分邏輯,調度器須要保持對時鐘跟蹤,由於積分的更新是基於時鐘。舉個栗子,子端口和流水線流量整形,流分類強制上限等等。
每當調度器決定發送一個報文給網卡TX的時候,調度器會相應地增長它的內部時鐘參考源。所以,以字節爲單位保持內部時鐘參考源是很方便的,尤爲是要求在物理接口的傳輸介質上發送一個字節來表示時間片的時候。這樣,當一個報文被調度到發送的時候,時鐘按(n + h)增長,n是報文長度的字節數,h是每一個報文的幀前導字節數。

(2)內部時鐘參考源再同步
調度器須要調整對齊端口傳輸帶上的內部時鐘參考源。緣由是爲了防止丟包,調度器不能給網卡TX喂大於物理介質線速的字節數。(丟包處理經過調度器,由於網卡TX輸入隊列滿了,或者隨後在網卡TX)
調度器讀取每個隊列調用的當前時間。CPU 時間戳能夠經過讀取TSC(Time Stamp Counter)寄存器或者HPET(high precision event timer)寄存器來獲取。當前CPU時間戳是從CPU時鐘字節數轉換而來的,time_bytes = time_cycles/cycles_per_byte.cycles_per_byte是CPU週期數,等於在電纜中傳輸一個字節的時間。(舉個栗子:一個CPU頻率爲2GHZ和一個10GbE端口,cycles_per_byte = 1.6)。
調度器維護了一個網卡時間的內核時鐘參考源。每當一個報文被調度時,網卡時間會按照報文長度(包含幀前導字節數)增長。每個出隊調用時,調度器會檢查它的網卡時間的內部參考源,相對於當前時間:
1.若是網卡時間在未來(即:網卡時間 >= 當前時間),不須要調整網卡時間。這意味着調度器有能力在網卡實際須要多少報文時去調度網卡上的報文,所以網卡TX能夠不少出路這些報文;
2.若是網卡時間在過去(即:網卡時間 < 當前時間),那麼網卡時間應該調整到當前時間,這意味着調度器不能保持網卡字節傳輸帶上的速度,所以網卡帶寬會由於網卡TX處理較少報文而浪費。

(3)調度器的精度(accuracy)和粒度(granularity)
調度器的往返延遲(SRTD)是經過調度器在同一個流水線上的兩個連續檢測的時間(CPU週期的數量)。爲了充分利用輸出端口(就是避免帶寬損失),調度器應該有能力在調度n個報文的速度上比網卡TX發送n個報文的速度要快。在假設流水線令牌桶沒有配置超額的狀況下,調度器要跟得上每一個獨立的流水線的速度。這意味着令牌桶的大小應該設置的足夠大才能防止由於過大的往返延遲(SRTD)溢出,由於這樣的話,會致使流水線的積分損失和帶寬損失。

11.積分規則(logic)
(1)調度決策
當下面所有條件都知足時,發送下一個報文(從子端口S,流水線P,流分類TC,隊列Q)到報文發送完成的調度決策是最佳的:
1.子端口S的流水線P是從當前端口(grinders)選擇的
2.流分類TC是流水線P活動的流分類裏優先級最高的
3.隊列Q是流水線P的流分類TC裏經過WRR選擇的下一個隊列
4.子端口S有足夠的積分去發送這個報文
5.子端口S有足夠的積分給流分類TC來發送這個報文
6.流水線P有足夠的積分去發送這個報文
7.流水線P有足夠的積分給流分類TC來發送這個報文
若是上述條件都知足了,那麼在子端口S,子端口S的流分類TC,流水線P,流水線P的流分類TC上要發送的報文和須要積分就會被扣除。數據結構

相關文章
相關標籤/搜索