Linux內核 RPS/RFS功能詳細測試分析

RPS和RFS

  • RPS 全稱是 Receive Packet Steering, 這是Google工程師 Tom Herbert ([email protected] )提交的內核補丁, 在2.6.35進入Linux內核. 這個patch採用軟件模擬的方式,實現了多隊列網卡所提供的功能,分散了在多CPU系統上數據接收時的負載, 把軟中斷分到各個CPU處理,而不需要硬件支持,大大提高了網絡性能。
  • RFS 全稱是 Receive Flow Steering, 這也是Tom提交的內核補丁,它是用來配合RPS補丁使用的,是RPS補丁的擴展補丁,它把接收的數據包送達應用所在的CPU上,提高cache的命中率。
  • 這兩個補丁往往都是一起設置,來達到最好的優化效果, 主要是針對單隊列網卡多CPU環境(多隊列多重中斷的網卡也可以使用該補丁的功能,但多隊列多重中斷網卡有更好的選擇:SMP IRQ affinity)

原理

RPS: RPS實現了數據流的hash歸類,並把軟中斷的負載均衡分到各個cpu,實現了類似多隊列網卡的功能。由於RPS只是單純的把同一流的數據包分發給同一個CPU核來處理了,但是有可能出現這樣的情況,即給該數據流分發的CPU核和執行處理該數據流的應用程序的CPU核不是同一個:數據包均衡到不同的cpu,這個時候如果應用程序所在的cpu和軟中斷處理的cpu不是同一個,此時對於cpu cache的影響會很大。那麼RFS補丁就是用來確保應用程序處理的cpu跟軟中斷處理的cpu是同一個,這樣就充分利用cpu的cache。

  • 應用RPS之前: 所有數據流被分到某個CPU, 多CPU沒有被合理利用, 造成瓶頸

  • 應用RPS之後: 同一流的數據包被分到同個CPU核來處理,但可能出現cpu cache遷躍

  • 應用RPS+RFS之後: 同一流的數據包被分到應用所在的CPU核

必要條件

使用RPS和RFS功能,需要有大於等於2.6.35版本的Linux kernel.

如何判斷內核版本?

1
2
$uname-r
2.6.38-2-686-bigmem

對比測試

類別 測試客戶端 測試服務端
型號 BladeCenter HS23p BladeCenter HS23p
CPU Xeon E5-2609 Xeon E5-2630
網卡 Broadcom NetXtreme II BCM5709S Gigabit Ethernet Emulex Corporation OneConnect 10Gb NIC
內核 3.2.0-2-amd64 3.2.0-2-amd64
內存 62GB 66GB
系統 Debian 6.0.4 Debian 6.0.5
超線程
CPU核 4 6
驅動 bnx2 be2net
  • 客戶端: netperf
  • 服務端: netserver
  • RPS cpu bitmap測試分類: 0(不開啓rps功能), one cpu per queue(每隊列綁定到1個CPU核上), all cpus per queue(每隊列綁定到所有cpu核上), 不同分類的設置值如下
  1. 0(不開啓rps功能)
    /sys/class/net/eth0/queues/rx-0/rps_cpus 00000000
    /sys/class/net/eth0/queues/rx-1/rps_cpus 00000000
    /sys/class/net/eth0/queues/rx-2/rps_cpus 00000000
    /sys/class/net/eth0/queues/rx-3/rps_cpus 00000000
    /sys/class/net/eth0/queues/rx-4/rps_cpus 00000000
    /sys/class/net/eth0/queues/rx-5/rps_cpus 00000000
    /sys/class/net/eth0/queues/rx-6/rps_cpus 00000000
    /sys/class/net/eth0/queues/rx-7/rps_cpus 00000000
    
    /sys/class/net/eth0/queues/rx-0/rps_flow_cnt 0
    /sys/class/net/eth0/queues/rx-1/rps_flow_cnt 0
    /sys/class/net/eth0/queues/rx-2/rps_flow_cnt 0
    /sys/class/net/eth0/queues/rx-3/rps_flow_cnt 0
    /sys/class/net/eth0/queues/rx-4/rps_flow_cnt 0
    /sys/class/net/eth0/queues/rx-5/rps_flow_cnt 0
    /sys/class/net/eth0/queues/rx-6/rps_flow_cnt 0
    /sys/class/net/eth0/queues/rx-7/rps_flow_cnt 0
    
    /proc/sys/net/core/rps_sock_flow_entries 0
  2. one cpu per queue(每隊列綁定到1個CPU核上)
    /sys/class/net/eth0/queues/rx-0/rps_cpus 00000001
    /sys/class/net/eth0/queues/rx-1/rps_cpus 00000002
    /sys/class/net/eth0/queues/rx-2/rps_cpus 00000004
    /sys/class/net/eth0/queues/rx-3/rps_cpus 00000008
    /sys/class/net/eth0/queues/rx-4/rps_cpus 00000010
    /sys/class/net/eth0/queues/rx-5/rps_cpus 00000020
    /sys/class/net/eth0/queues/rx-6/rps_cpus 00000040
    /sys/class/net/eth0/queues/rx-7/rps_cpus 00000080
    
    /sys/class/net/eth0/queues/rx-0/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-1/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-2/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-3/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-4/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-5/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-6/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-7/rps_flow_cnt 4096
    
    /proc/sys/net/core/rps_sock_flow_entries 32768
  3. all cpus per queue(每隊列綁定到所有cpu核上)
    /sys/class/net/eth0/queues/rx-0/rps_cpus 000000ff
    /sys/class/net/eth0/queues/rx-1/rps_cpus 000000ff
    /sys/class/net/eth0/queues/rx-2/rps_cpus 000000ff
    /sys/class/net/eth0/queues/rx-3/rps_cpus 000000ff
    /sys/class/net/eth0/queues/rx-4/rps_cpus 000000ff
    /sys/class/net/eth0/queues/rx-5/rps_cpus 000000ff
    /sys/class/net/eth0/queues/rx-6/rps_cpus 000000ff
    /sys/class/net/eth0/queues/rx-7/rps_cpus 000000ff
    
    /sys/class/net/eth0/queues/rx-0/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-1/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-2/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-3/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-4/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-5/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-6/rps_flow_cnt 4096
    /sys/class/net/eth0/queues/rx-7/rps_flow_cnt 4096
    
    /proc/sys/net/core/rps_sock_flow_entries 32768

測試方法: 每種測試類型執行3次,中間睡眠10秒, 每種測試類型分別執行100、500、1500個實例, 每實例測試時間長度爲60秒

  • TCP_RR 1 byte: 測試TCP 小數據包 request/response的性能
    1
    netperf -t TCP_RR -H $serverip -c -C -l 60
  • UDP_RR 1 byte: 測試UDP 小數據包 request/response的性能
    1
    netperf -t UDP_RR -H $serverip -c -C -l 60
  • TCP_RR 256 byte: 測試TCP 大數據包 request/response的性能
    1
    netperf -t TCP_RR -H $serverip -c -C -l 60 -- -r256,256
  • UDP_RR 256 byte: 測試UDP 大數據包 request/response的性能
    1
    netperf -t UDP_RR -H $serverip -c -C -l 60 -- -r256,256

TPS測試結果

  • TCP_RR 1 byte小包測試結果

  • TCP_RR 256 byte大包測試結果

  • UDP_RR 1 byte小包測試結果

  • UDP_RR 256 byte大包測試結果

CPU負載變化

在測試過程中,使用mpstat收集各個CPU核的負載變化

  1. 關閉RPS/RFS: 可以看出關閉RPS/RFS時,軟中斷的負載都在cpu0上,並沒有有效的利用多CPU的特性,導致了性能瓶頸
    Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
    Average:     all    3.65    0.00   35.75    0.05    0.01   14.56    0.00    0.00   45.98
    Average:       0    0.00    0.00    0.00    0.00    0.00  100.00    0.00    0.00    0.00
    Average:       1    4.43    0.00   37.76    0.00    0.11   11.49    0.00    0.00   46.20
    Average:       2    5.01    0.00   45.80    0.00    0.00    0.00    0.00    0.00   49.19
    Average:       3    5.11    0.00   45.07    0.00    0.00    0.00    0.00    0.00   49.82
    Average:       4    3.52    0.00   40.38    0.14    0.00    0.00    0.00    0.00   55.96
    Average:       5    3.85    0.00   39.91    0.00    0.00    0.00    0.00    0.00   56.24
    Average:       6    3.62    0.00   40.48    0.14    0.00    0.00    0.00    0.00   55.76
    Average:       7    3.87    0.00   38.86    0.11    0.00    0.00    0.00    0.00   57.16
  2. 每隊列關聯到一個CPU TCP_RR: 可以看出軟中斷負載已經能分散到各個CPU核上,有效利用了多CPU的特性,大大提高了系統的網絡性能
    Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
    Average:     all    5.58    0.00   59.84    0.01    0.00   22.71    0.00    0.00   11.86
    Average:       0    2.16    0.00   20.85    0.00    0.04   72.03    0.00    0.00    4.93
    Average:       1    4.68    0.00   46.27    0.00    0.00   42.73    0.00    0.00    6.32
    Average:       2    6.76    0.00   63.79    0.00    0.00   11.03    0.00    0.00   18.42
    Average:       3    6.61    0.00   65.71    0.00    0.00   11.51    0.00    0.00   16.17
    Average:       4    5.94    0.00   67.83    0.07    0.00   11.59    0.00    0.00   14.58
    Average:       5    5.99    0.00   69.42    0.04    0.00   12.54    0.00    0.00   12.01
    Average:       6    5.94    0.00   69.41    0.00    0.00   12.86    0.00    0.00   11.78
    Average:       7    6.13    0.00   69.61    0.00    0.00   14.48    0.00    0.00    9.77
  3. 每隊列關聯到一個CPU UDP_RR: CPU負載未能均衡的分佈到各個CPU, 這是由於網卡hash計算在UDP包上的不足, 詳細請見本文後記部分
    Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
    Average:     all    3.01    0.00   29.84    0.07    0.01   13.35    0.00    0.00   53.71
    Average:       0    0.00    0.00    0.08    0.00    0.00   90.01    0.00    0.00    9.91
    Average:       1    3.82    0.00   32.87    0.00    0.05   12.81    0.00    0.00   50.46
    Average:       2    4.84    0.00   37.53    0.00    0.00    0.14    0.00    0.00   57.49
    Average:       3    4.90    0.00   37.92    0.00    0.00    0.16    0.00    0.00   57.02
    Average:       4    2.57    0.00   32.72    0.20    0.00    0.09    0.00    0.00   64.42
    Average:       5    2.66    0.00   33.54    0.11    0.00    0.08    0.00    0.00   63.60
    Average:       6    2.75    0.00   32.81    0.09    0.00    0.06    0.00    0.00   64.30
    Average:       7    2.71    0.00   32.66    0.17    0.00    0.06    0.00    0.00   64.40
  4. 每隊列關聯到所有CPU: 可以看出軟中斷負載已經能分散到各個CPU核上,有效利用了多CPU的特性,大大提高了系統的網絡性能
    Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
    Average:     all    5.39    0.00   59.97    0.00    0.00   22.57    0.00    0.00   12.06
    Average:       0    1.46    0.00   21.83    0.04    0.00   72.08    0.00    0.00    4.59
    Average:       1    4.45    0.00   46.40    0.00    0.04   43.39    0.00    0.00    5.72
    Average:       2    6.84    0.00   65.62    0.00    0.00   11.39    0.00    0.00   16.15
    Average:       3    6.71    0.00   67.13    0.00    0.00   12.07    0.00    0.00   14.09
    Average:       4    5.73    0.00   66.97    0.00    0.00   10.71    0.00    0.00   16.58
    Average:       5    5.74    0.00   68.57    0.00    0.00   13.02    0.00    0.00   12.67
    Average:       6    5.79    0.00   69.27    0.00    0.00   12.31    0.00    0.00   12.63
    Average:       7    5.96    0.00   68.98    0.00    0.00   12.00    0.00    0.00   13.06

結果分析

以下結果只是針對測試服務器特定硬件及系統的數據,在不同測試對象的RPS/RFS測試結果可能有不同的表現

TCP性能:

  • 在沒有打開RPS/RFS的情況下,隨着進程數的增加,TCP tps性能並明顯沒有提升,在184~188k之間。
  • 打開RPS/RFS之後,隨着RPS導致軟中斷被分配到所有CPU上和RFS增加的cache命中, 小數據包(1字節)及大數據包(256字節,相對小數據包而言, 而不是實際應用中的大數據包)的tps性能都有顯著提升
  • 100個進程提升40%的性能(兩種RPS/RFS設置的性能結果一致), cpu負載升高40%
  • 500個進程提升70%的性能(兩種RPS/RFS設置的性能結果一致), cpu負載升高62%
  • 1500個進程提升75%的性能(兩種RPS/RFS設置的性能結果一致), cpu負載升高77%



UDP性能:

  • 在沒有打開RPS/RFS的情況下,隨着進程數的增加,UDP tps性能並明顯沒有提升,在226~235k之間。
  • 打開RPS/RFS之後,,隨着RPS導致軟中斷被分配到所有CPU上和RFS增加的cache命中, 小數據包(1字節)及大數據包(256字節,相對小數據包而言, 而不是實際應用中的大數據包)的TPS性能, 在每隊列關聯到所有CPU的情況下有顯著提升, 而每隊列關聯到一個CPU後反倒是導致了UDP tps性能下降1% (這是bnx2網卡不支持UDP port hash及此次測試的侷限性造成的結果, 詳細分析見: 後記)
  • 每隊列關聯到所有CPU的情況下, 在100個進程時小包提升40%的性能, cpu負載升高60%; 大包提升33%, cpu負載升高47%
  • 每隊列關聯到所有CPU的情況下, 在500個進程提小包提升62%的性能, cpu負載升高71%; 大包提升60%, cpu負載升高65%
  • 每隊列關聯到所有CPU的情況下, 在1500個進程提升65%的性能, cpu負載升高75%; 大包提升64%, cpu負載升高74%

後記

UDP在每隊列綁定到一個CPU時性能下降,而綁定到所有CPU時,卻有性能提升,這一問題涉及到幾個因素,當這幾個因素湊一起時,導致了這種奇特的表現。

  • 此次測試的侷限性:本次測試是1對1的網絡測試,產生的數據包的IP地址都是相同的
  • bnx2網卡在RSS hash上,不支持UDP Port,也就是說,網卡在對TCP數據流進行隊列選擇時的hash包含了ip和port, 而在UDP上的hash, 只有IP地址,導致了本次測試(上面的侷限性影響)的UDP數據包的hash結果都是一樣的,數據包被轉送到同一條隊列。
  • 單單上面兩個因素,還無法表現出UDP在每隊列綁定到一個CPU時性能下降,而綁定到所有CPU時,卻有性能提升的現象。 因爲RPS/RFS本身也有hash計算,也就是進入隊列後的數據包,還需要經過RPS/RFS的hash計算(這裏的hash支持udp port), 然後進行第二次數據包轉送選擇;如果每隊列綁定到一個CPU, 系統直接跳過第二次hash計算,數據包直接分配到該隊列關聯的CPU處理,也就導致了在第一次hash計算後被錯誤轉送到某一隊列的UDP數據包,將直接送到cpu處理,導致了性能的下降; 而如果是每隊列綁定到所有CPU, 那麼進入隊列後的數據包會在第二次hash時被重新分配,修正了第一次hash的錯誤選擇。

相關對比測試

1. SMP IRQ affinity: http://www.igigo.net/archives/231

參考資料


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章