Try   HackMD

以 Linux XDP 為基礎的高效率網路負載平衡器

contributed by < foxhoundsk >

tags: linux2020

Benchmarking

HAProxy:

./wrk -t8 -c250 -d60s -R20000 --latency http://10.10.0.2 

  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.08ms  480.11us   8.56ms   66.27%
    Req/Sec     2.64k   295.71     4.89k    71.14%
  Latency Distribution (HdrHistogram - Recorded Latency)
 50.000%    1.06ms
 75.000%    1.40ms
 90.000%    1.71ms
 99.000%    2.28ms
 99.900%    2.95ms
 99.990%    4.11ms
 99.999%    7.35ms
100.000%    8.57ms

#[Mean    =        1.080, StdDeviation   =        0.480]
#[Max     =        8.560, Total count    =       996911]
#[Buckets =           27, SubBuckets     =         2048]
----------------------------------------------------------
  1198537 requests in 1.00m, 428.63MB read
Requests/sec:  19975.33
Transfer/sec:      7.14MB

XDP:

./wrk -t8 -c250 -d60s -R20000 --latency http://10.10.0.5

Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.89ms  413.29us   8.80ms   64.24%
    Req/Sec     2.65k   280.36     4.20k    73.29%
  Latency Distribution (HdrHistogram - Recorded Latency)
 50.000%    0.88ms
 75.000%    1.19ms
 90.000%    1.42ms
 99.000%    1.86ms
 99.900%    2.16ms
 99.990%    2.62ms
 99.999%    6.59ms
100.000%    8.81ms

#[Mean    =        0.885, StdDeviation   =        0.413]
#[Max     =        8.800, Total count    =       996909]
#[Buckets =           27, SubBuckets     =         2048]
----------------------------------------------------------
  1198574 requests in 1.00m, 456.02MB read
Requests/sec:  19976.16
Transfer/sec:      7.60MB

參數 -R20000 為目前實驗的瓶頸,應再調高,方可展現較低 latency 所帶來的效益(higher throughput)。

嘗試參數:

./wrk -t6 -c250 -d60s -R150000 --latency http://10.10.0.5

XDP:

Thread Stats   Avg      Stdev     Max   +/- Stdev 
    Latency     4.09s     1.79s   11.73s    63.18% 
    Req/Sec    22.22k   802.67    24.06k    66.36%                
  Latency Distribution (HdrHistogram - Recorded Latency)                                                                               
 50.000%    3.91s      
 75.000%    5.37s 
 90.000%    6.59s 
 99.000%    8.34s 
 99.900%    9.58s 
 99.990%   11.65s 
 99.999%   11.72s 
100.000%   11.74s
----------------------------------------------------------
  7948712 requests in 1.00m, 2.97GB read
Requests/sec: 132479.84
Transfer/sec:     50.66MB

haproxy:

Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    17.37s     7.55s   36.01s    59.98%      
    Req/Sec    12.40k   328.25    13.15k    66.67%      
  Latency Distribution (HdrHistogram - Recorded Latency)
 50.000%   17.20s                                                  
 75.000%   23.63s                                                  
 90.000%   27.16s                                                  
 99.000%   34.50s                                                  
 99.900%   35.78s                                                  
 99.990%   35.95s                   
 99.999%   36.01s
----------------------------------------------------------
  4461288 requests in 1.00m, 1.57GB read
Requests/sec:  74353.80
Transfer/sec:     26.73MB

筆記

實驗環境佈置

目前架構為,經過 IP in IP 包裝過的封包到達其他 LB 時,其他 LB 會將 IPIP header 截斷,使得封包在該 LB 上 (application, network stack 等等) 看起來就只是一個普通的 IP packet,最後,封包處理完後將直接以 VIP 的 IP 位置回傳給 client,而非實際 IP。

在此環境下,每台 LB 要設定其負責的 VIP,設定方式為將 VIP 新增到 loopback device 上,即:

$ ip addr add 10.10.0.5/8 dev lo

其中 10.10.0.5 即為 VIP。

此外,我們還要對 ARP 做相關設定:

sysctl net.ipv4.conf.all.arp_ignore=1
sysctl net.ipv4.conf.eth0.arp_ignore=1
sysctl net.ipv4.conf.all.arp_announce=2
sysctl net.ipv4.conf.eth0.arp_announce=2

如此一來 VIP 才能正確做出 DSR (Direct Server Return),也就是以 VIP 作為 L3 中的 source address。

ECMP Linux 設定

此機器用於將 ingress 的流量平均分發至個別 XDP LB,關於 ECMP 在 vanilla Linux 上的發展歷史可見此連結

首先,我們假設 10.10.0.7VIP、做 ECMP 的機器的位置為 10.10.0.3、XDP LB \ application 機器的位置為 10.10.0.4, 10.10.0.5 以及 10.10.0.6、做 benchmarking 的 client 的位置為 10.10.0.2

  • ECMP 的機器主要會有以下設定:

    ​​​​ip route add 10.10.0.7/32 nexthop via 10.10.0.4 weight 1 \
    ​​​​nexthop via 10.10.0.5 weight 1 \
    ​​​​nexthop via 10.10.0.6 weight 1
    
    ​​​​sysctl net.ipv4.ip_forward=1
    

    其中需注意 nexthop 的位置必須是 reachable 的,倘若不是,可參考 onlink 這個 iproute2 route 的其中一個參數是否對你的環境設定有幫助。

    ip_forward 用於將 MAC address 指向本機上的 interface 但 L3 的位置不屬於本機的封包轉送至其他機器。

    設定完後執行命令 $ ip r 預期會見到以下輸出:

    ​​​​# ip r
    ​​​​10.10.0.0/24 dev eth0 proto kernel scope link src 10.10.0.3 
    ​​​​10.10.0.7 
    ​​​​nexthop via 10.10.0.4 dev eth0 weight 1 
    ​​​​nexthop via 10.10.0.5 dev eth0 weight 1 
    ​​​​nexthop via 10.10.0.6 dev eth0 weight 1
    
  • Benchmarking 機器設定:

    ​​​​ip route add 10.10.0.7 via 10.10.0.3
    

    強制將指向 10.10.0.7 的封包發送給 10.10.0.3 這台機器(做 ECMP 的機器),讓它去做 routing。

  • XDP LB / application 機器設定請參考上一段落的介紹。

LACP vs. ECMP

雖然兩者均用於負載平衡以及增加線路的冗餘性,但前者是作用於 layer 2,而後者則是作用於 layer 3。

建立 (socket(2)) netlink socket 時,SOCK_RAW 以及 SOCK_DGRAM 這兩種 socket 類型均可使用,因為 netlink 將其視為等價。

注意,載入 XDP program 時,相關 bpf 系統呼叫的成功僅是代表 XDP program 已載入到核心中(通過 in-kernel verifier 的檢測),此時 XDP program 尚未掛載(hook)到預期的 network interface 上,我們需要使用 netlink 中的 NETLINK_ROUTE 相關功能方能將 XDP program 掛載到預期的 interface 上。

值得注意的是,libbpf 已經實做了 XDP program 相關的 netlink 的 helper。

capabilities negotiation

因為每個 driver 所支援的 XDP capabilities 不一,所以當載入 XDP program 時,需檢查對應的 NIC device driver 是否支援此 XDP program 需要用到的功能。

ebpf helper function

epbf program 若需使用 kernel API,則該 API 需經類似 EXPORT_SYMBOL 的巨集處理。

每種 ebpf program type 有個別可使用的 helper function 子集。

packet redirection

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

(Facebook netdevconf2.1)

HW offload

原生 NIC driver (eBPF driver mode) 對 eBPF 的應用有些限制,例如:僅能有 31 個 NIC ring buffer (單埠網卡),雙埠網卡的話 ring 的數量限制則僅有 15 個。

若將 NIC 的 driver 更換 (載入對應核心模組) 為對 eBPF 提供支援的 driver,則可以不受此限制的約束。

OSI

src & dst IP 位於 L3,src & dst port 位於 L4。

IPv4 header

因 header 中的 option 成員的關係,header 的長度不定。長度由 4-bit 的 bitfield (在結構體中名為 ihl) 來定義,ihl 表示 header 長度為多少個 dword (32-bit)。

由於長度使用 4 個位元表示,並且除了 option 成員外 header 還有必要的長度。因此 IPv4 長度最小為 20 bytes,最大為 60 bytes (0b1111 * size_of_qword)。

參考資料