Cilium 網絡性能分析

作者:Thomas Graf
譯者:羅煜、張亮,均來自 KubeSphere 團隊
Thomas Graf 是 Cilium 的聯合創始人,同時也是 Cilium 母公司 Isovalent[1] 的 CTO 和聯合創始人。此前 Thomas 曾先後在 Linux 內核 [2] 的網絡、安全和 eBPF 領域從事了 15 年的開發工作。

注:本文已取得作者本人的翻譯授權!

原文鏈接:https://cilium.io/blog/2021/05/11/cni-benchmark

大家好!👋

隨着越來越多的關鍵負載被遷移到 Kubernetes 上,網絡性能基準測試正在成爲選擇 Kubernetes 網絡方案的重要參考。在這篇文章中,我們將基於過去幾周進行的大量基準測試的結果探討 Cilium 的性能特點。應廣大用戶的要求,我們也將展示 Calico 的測試結果,以便進行直接對比。

除了展示測試的結果數據外,我們還將對容器網絡基準測試這一課題進行更深入的研究,並探討以下幾個方面的問題:

測試結果彙總

在詳細分析基準測試及其數據之前,我們先展示彙總的測試結論。如果您希望直接瞭解測試細節並得出自己的結論,也可以跳過這一節的內容。

吞吐量基準測試

免責聲明:

基準測試難度很大。測試結果很大程度上依賴於運行測試的硬件環境。除非是在相同的系統上收集的結果,否則不應直接用絕對的數值進行比較。

讓我們從最常見和最明顯的 TCP 吞吐量基準測試開始,測量運行在不同節點上的容器之間的最大數據傳輸速率。

bench tcp stream 1 stream

上圖顯示了單個 TCP 連接可實現的最大吞吐量,最優的幾個配置性能剛好超過了 40 Gbit/s。以上結果由 netperfTCP_STREAM 測試得出,測試環境使用了速率爲 100 Gbit/s 的網口以確保網卡不會成爲瓶頸。由於運行單個 netperf 進程通過單個 TCP 連接傳輸數據,大部分的網絡處理是由單個 CPU 核心完成的。這意味着上面的最大吞吐量受到單個核心的可用 CPU 資源限制,因此可以顯示當 CPU 成爲瓶頸時每個配置可以實現的吞吐量。本文後面將會進一步擴展測試,使用更多的 CPU 核心來消除 CPU 資源的限制。

使用高性能 eBPF 實現的吞吐量甚至略高於節點到節點的吞吐量。這令人非常意外。通常普遍認爲,相較於節點到節點的網絡,容器網絡會帶來額外的開銷。我們暫時先把這個疑惑擱置一旁,進一步研究之後再來分析這個問題。

100 Gbit/s 傳輸速率所需的 CPU 資源

TCP_STREAM 基準測試的結果已經暗示了哪些配置可以最有效地實現高傳輸速率,但我們還是看一下運行基準測試時系統整體的 CPU 消耗。

bench tcp stream 1 stream cpu

上圖顯示了達到 100 Gbit/s 吞吐量整個系統所需的 CPU 使用率。請注意,這不同於前一個圖中吞吐量對應的 CPU 消耗。在上圖中,所有的 CPU 使用率都已折算爲傳輸速率穩定在 100 Gbit/s 時的數值以便可以直接對比。上圖中的條形圖越短,對應的配置在 100 Gbit/s 傳輸速率時的效率越高。

注意:TCP 流的性能通常受到接收端的限制,因爲發送端可以同時使用 TSO 大包。這可以從上述測試中服務器側增加的 CPU 開銷中觀察到。

TCP 吞吐量基準測試的意義

雖然大多數用戶不太可能經常遇到上述的吞吐量水平,但這樣的基準測試對特定類型的應用程序有重要意義:

在本文後面的章節,我們將繼續深入討論測量延遲:每秒請求數 [3] 和新連接處理速率 [4],以更好地展示典型微服務工作負載的性能特點。

容器網絡是否會增加開銷

在第一個基準測試的分析中我們提到,與節點網絡相比,容器網絡會帶來一些額外開銷。這是爲什麼呢?讓我們從架構的角度來對比這兩種網絡模型。

container overhead

上圖表明容器網絡也需要執行節點到節點網絡的所有處理流程,並且這些流程都發生在容器的網絡命名空間中(深藍色部分)。

由於節點網絡的處理工作也需要在容器網絡命名空間內進行,在容器網絡命名空間之外的任何工作本質上都是額外開銷。上圖顯示了使用 Veth 設備時,Linux 路由的網絡路徑。如果您使用 Linux 網橋或 OVS,網絡模型可能略有不同,但它們基本的開銷點是相同的。

打破常規:eBPF 主機路由(Host-Routing)

在上面的基準測試中,您也許會疑惑 Cilium eBPF 和 Cilium eBPF 傳統主機路由(Legacy Host Routing)兩種配置的區別,以及爲什麼原生的 Cilium eBPF 數據路徑會比主機路由快得多。原生的 Cilium eBPF 數據路徑是一種被稱爲 eBPF 主機路由的優化數據路徑,如下圖所示:

ebpf hostrouting

eBPF 主機路由允許繞過主機命名空間中所有的 iptables 和上層網絡棧,以及穿過 Veth 對時的一些上下文切換,以節省資源開銷。網絡數據包到達網絡接口設備時就被儘早捕獲,並直接傳送到 Kubernetes Pod 的網絡命名空間中。在流量出口側,數據包同樣穿過 Veth 對,被 eBPF 捕獲後,直接被傳送到外部網絡接口上。eBPF 直接查詢路由表,因此這種優化完全透明,並與系統上運行的所有提供路由分配的服務兼容。關於如何啓用該特性,請參閱調優指南中的 eBPF 主機路由 [5]。

Calico eBPF 正在將一些類似的繞過方法用於 iptables,但這與 Cilium 的原理並不完全相同,文章後面會進一步介紹。不管如何,測試結果證明繞過緩慢的內核子系統(例如 iptables)可以帶來極大的性能提升。

逼近 100 Gbit/s 的線速率(Line Rate)

在上文中,我們分析了只涉及一個 CPU 核心的基準測試結果。接下來我們將放開單核的限制,將 TCP 流並行化以運行多個 netperf 進程。

bench tcp stream 32 streams

注意:由於硬件有 32 個線程,我們特意選擇了 32 個進程,以確保系統能夠均勻地分配負載。

上圖並沒有提供十分有價值的信息,僅僅表明如果投入足夠多的 CPU 資源,所有測試配置都能達到接近 100 Gbit/s 的線速率。然而,從 CPU 資源來看,我們仍然可以發現效率上的差異。

bench tcp stream 32 streams cpu

請注意,上圖中的 CPU 使用率涵蓋了全部的 CPU 消耗,包括正在運行的 netperf 進程的消耗,也包括工作負載執行網絡 I/O 所需的 CPU 資源。然而,它並不包括應用程序通常需要執行的任何業務邏輯所帶來的 CPU 消耗。

測量延遲:每秒請求數

每秒請求數與吞吐量指標幾乎完全相反。它可以衡量單個 TCP 持久連接上按順序的單字節往返的傳輸速率。此基準測試可以體現網絡數據包的處理效率。單個網絡數據包的延遲越低,每秒可處理的請求就越多。吞吐量和延遲的共同優化通常需要進行權衡。爲了獲得最大的吞吐量,較大的緩衝區是理想的選擇,但是較大的緩衝區會導致延遲增加。這一現象被稱爲緩衝區膨脹。Cilium 提供了一個稱爲帶寬管理器(Bandwidth Manager)[6] 的功能,該功能可以自動配置公平隊列,可實現基於最早發出時間的 Pod 速率限制,併爲服務器工作負載優化 TCP 棧設置,使吞吐量和延遲之間達到最佳平衡。

這個基準測試經常被忽視,但它對用戶來說通常比想象的重要得多,因爲它模擬了一種十分常見的微服務使用模式:使用持久化的 HTTP 或 gRPC 連接在 Service 之間發送請求和響應。

下圖顯示單個 netperf 進程執行 TCP_RR 測試時,不同配置的性能表現:

bench tcp rr 1 process

在這個測試中表現更好的配置也實現了更低的平均延遲。然而,這並不足以讓我們對 P95 或 P99 延遲得出結論。我們將在未來的博客文章中探討這些問題。

bench tcp rr 1 process cpu

我們進一步測試運行 32 個並行的 netperf 進程以利用所有可用的 CPU 核心。可以看到,所有配置的性能都有所提升。然而,與吞吐量測試不同的是,在本測試中投入更多的 CPU 資源並不能彌補效率上的欠缺,因爲最大處理速率受延遲而非可用 CPU 資源限制。即便網絡帶寬成爲瓶頸,我們也會看到相同的每秒請求數值。

bench tcp rr 32 processes

總體而言,結果非常鼓舞人心,Cilium 可以在我們的測試系統上通過 eBPF 主機路由實現近 1,000,000 請求每秒的處理速率。

bench tcp rr 32 processes cpu

Cilium eBPF 和 Calico eBPF 的 CPU 火焰圖對比

總體而言,Cilium eBPF 和 Calico eBPF 的性能基本相同。這是因爲它們使用了相同的數據路徑嗎?並不是。並不存在預定義的 eBPF 數據路徑。eBPF 是一種編程語言和運行時引擎,它允許構建數據路徑特性和許多其他特性。Cilium 和 Calico eBPF 數據路徑差異很大。事實上,Cilium 提供了很多 Calico eBPF 不支持的特性。但即使是在與 Linux 網絡棧的交互上,兩者也有顯着的差異。我們可以通過二者的 CPU 火焰圖來來進一步分析。

Cilium eBPF(接收路徑)

cilium flamegraph zoom

Cilium 的 eBPF 主機路由提供了很好的免上下文切換的數據傳送途徑(從網卡到應用程序的套接字)。這就是爲什麼在上面的火焰圖中整個接收端路徑能夠很好地匹配到一張火焰圖中。火焰圖也顯示了 eBPF、TCP/IP 和套接字的處理塊。

Calico eBPF(接收路徑)

Calico eBPF 接收端看起來卻不太一樣。雖然有着相同的 eBPF 處理塊執行 eBPF 程序,但 Calico eBPF 接收路徑穿過了額外的 Veth,這在 Cilium eBPF 數據路徑接收端並不需要。

calico flamegraph zoom1

上圖中的處理仍然在主機的上下文中執行。下面的這火焰圖顯示了 Pod 中被 process_backlog 恢復執行的工作。雖然這與 Cilium 場景下的工作一樣(都是 TCP/IP + 套接字數據傳送),但因爲穿過了 Veth 從而需要額外的上下文切換。

calico flamegraph zoom2

如果您希望自己進行更進一步的研究,可以點擊以下鏈接打開交互式的火焰圖 SVG 文件查看細節:

新連接處理速率

連接處理速率基準測試基於每秒請求數的基準測試,但爲每個請求都建立了新的連接。此基準測試的結果顯示了使用持久連接和爲每個請求創建新連接兩種方式的性能差別。創建新 TCP 連接需要涉及系統中的多個組件,所以這個測試是目前對整個系統壓力最大的測試。通過這個基準測試,我們可以看到,充分利用系統中大多數的可用資源是可能的。

這個測試展示了一個接收或發起大量 TCP 連接的工作負載。典型的應用場景是由一個公開暴露的服務處理大量客戶端請求,例如 L4 代理或服務爲外部端點(例如數據抓取器)創建多個連接。這個基準測試能夠在卸載到硬件的工作最少的情況下儘可能地壓測系統,從而顯示出不同配置的最大性能差異。

首先,我們運行一個 netperf 進程來進行 TCP_CRR 測試。

bench tcp crr 1 process

在單個進程下不同配置的性能差異已經十分巨大,如果使用更多的 CPU 核心差異還將進一步擴大。同時也可以明顯看出,Cilium 再次能夠彌補網絡命名空間額外開銷造成的性能損失並達到和基線配置幾乎相同的性能。

bench tcp crr 1 process cpu

後續計劃:這個 CPU 資源使用率讓我們很驚訝並促使我們在接下來 1.11 的開發週期做進一步研究。似乎只要涉及到網絡命名空間的使用,發送端的資源開銷總是必不可少的。這一開銷在所有涉及網絡命名空間的配置中都存在,所以很有可能是由 Cilium 和 Calico 都涉及的內核數據路徑造成的。我們會及時更新這部分研究的進展。

當並行運行 32 個進行 TCP_CRR 測試的 netpert 進程以利用所有 CPU 核心時,我們觀察到了一個非常有意思的現象。

bench tcp crr 32 processes

基線配置的連接處理速率顯着下降。基線配置的性能並沒有隨着可用 CPU 資源的增多而進一步提升,儘管連接跟蹤狀態表大小發生了相應變化並且我們確認並沒有發生因連接跟蹤表記錄達到上限而導致的性能降低。我們重複進行了多次相同的測試,結果仍然相同。當我們手動通過 -j NOTRACK 規則繞過 iptables 連接跟蹤表時,問題立刻解決了,基線配置性能恢復到 200,000 連接每秒。所以很明顯,一旦連接數超過某個閾值,iptables 連接跟蹤表就會開始出現問題。

注意:在這個測試中,Calico eBPF 數據路徑的測試結果一直不是很穩定。我們目前還不清楚原因。網絡數據包的傳輸也不是很穩定。我們沒有將測試結果納入考慮,因爲測試結果不一定準確。我們邀請 Calico 團隊和我們一起研究這個問題並重新進行測試。

鑑於我們使用的是未經修改的標準應用程序來處理請求和傳輸信息,每秒處理 200,000 連接是一個非常優秀的成績。不過,我們還是看一下 CPU 的消耗。

bench tcp crr 32 processes cpu

這個基準測試結果顯示了不同配置的最大性能差異。爲了達到每秒處理 250,000 新連接的目標,整個系統必須消耗 33% 到 90% 的可用資源。

由於發送端 CPU 資源消耗一直高於接收端,我們可以確信相同資源下每秒能接收的連接數要大於每秒能發起的連接數。

WireGuard 與 IPsec 加密開銷對比

可能所有人都會認爲 WireGuard 的性能會優於 IPsec,所以我們先測試 WireGuard 在不同的最大傳輸單元(MTU)下的性能。

bench wireguard tcp 1 stream

不同的配置之間有一些差異。值得注意的是,Cilium 與 kube-proxy 的組合比單獨 Cilium 的性能更好。然而,這個性能差異相對較小並且基本可以通過優化 MTU 彌補。

以下是 CPU 資源的消耗:

bench wireguard tcp 1 stream cpu

上述結果表明在 MTU 相同的情況下,不同配置之間的 CPU 使用率差異很小,因而可以通過優化 MTU 配置獲得最佳性能。我們還對每秒請求數進行了測試,得到的結果也相同。感興趣的讀者可以參閱 Cilium 文檔的 CNI 性能基準測試 [11] 章節。

WireGuard 與 IPsec 對比

對 Wireguard 和 IPsec 的性能進行比較更加有趣。Cilium 支持 IPsec 已經有一段時間了。從 1.10 開始,Cilium 也開始支持 WireGuard。在其他方面相同的情況下,把這兩個加密方案放在一起進行對比,結果一定會非常有趣。

bench wireguard ipsec tcp stream 1 stream

不出所料,WireGuard 的吞吐量更高,並且在兩種 MTU 配置下,WireGuard 的最大傳輸速率更高。

下面繼續測試當吞吐量達到 10 Gbit/s 時,WireGuard 和 IPsec 在不同的 MTU 配置下的 CPU 使用率。

bench wireguard ipsec tcp stream 1 stream cpu

雖然 WireGuard 的最大吞吐量更高,但 IPsec 在吞吐量相同的情況下 CPU 開銷更小從而更有效率,這個差異非常巨大。

注意:爲了實現 IPsec 的高效率,需要使用支持 AES-NI 指令集的硬件來卸載 IPsec 的加密工作。
後續計劃:目前我們還不清楚爲什麼 IPsec 的高效率沒有帶來更高的吞吐量。使用更多的 CPU 核心也沒有明顯提升性能。這很可能是由於 RSS 不能很好地跨 CPU 核心處理加密流量,因爲通常用於哈希和跨 CPU 核心分配流量的 L4 信息是加密的,無法解析。因此,從哈希的角度來看,所有的連接都是一樣的,因爲在測試中只利用了兩個 IP 地址。

這是否會影響延遲?讓我進一步研究。延遲基準測試最能準確地描述微服務工作負載的實際狀況,微服務工作負載通常都會使用持久連接來交換請求和響應。

bench wireguard ipsec tcp rr 1 process

CPU 效率與觀察到的每秒請求數相符。然而,每個配置總共消耗的 CPU 資源都不是很高。相比 CPU 消耗方面的差異,延遲方面的差異更爲顯著。

bench wireguard ipsec tcp rr 1 process cpu

測試環境

以下是我們使用的裸機配置。我們搭建了兩套完全一樣的互相直連的系統。

除非特別說明,所有測試都使用了標準的 1500 字節 MTU。雖然 MTU 的值越高,測試結果的絕對數值會越好,但本文的基準測試的目的在於比較相對差異,而不是測試最高或最低性能的絕對數值。

測試配置

應廣大用戶的要求,我們展示了 Calico 的測試結果以便進行對比。爲了儘可能清晰地進行對比,我們使用了以下配置類型進行測試:

復現測試結果

測試所用的全部腳本都已經上傳到 GitHub 倉庫 cilium/cilium-perf-networking[13] 中,可用於復現測試結果。

下一步

我們在性能調優方面已經取得了不少結果,但我們還有許多其他的想法並將進一步優化 Cilium 各方面的性能。

更多信息

腳註

[1]

Isovalent: https://isovalent.com

[2]

Linux 內核: https://kernel.org

[3]

測量延遲:每秒請求數: #測量延遲:每秒請求數(Requests-per-Second)

[4]

新連接處理速率: #新連接處理速率

[5]

eBPF 主機路由: https://docs.cilium.io/en/latest/operations/performance/tuning/#ebpf-host-routing

[6]

帶寬管理器(Bandwidth Manager): https://docs.cilium.io/en/latest/operations/performance/tuning/#bandwidth-manager

[7]

Cilium eBPF SVG 火焰圖 - 發送端: https://cilium.io/b85c71fbc3ce620c8544c9317f2bf858/cilium-ebpf-hr-rr-zh3.svg

[8]

Cilium eBPF SVG 火焰圖 - 接收端: https://cilium.io/67a828b79d79f0360468cc02810c10e0/cilium-ebpf-hr-rr-zh4.svg

[9]

Calico eBPF SVG 火焰圖 - 發送端: https://cilium.io/3680690af3f6b5827065c0181025861e/calico-ebpf-rr-zh3.svg

[10]

Calico eBPF SVG 火焰圖 - 接收端: https://cilium.io/cc3abd245b9bc7bf5bcab5bf04c18f29/calico-ebpf-rr-zh4.svg

[11]

CNI 性能基準測試: https://docs.cilium.io/en/latest/operations/performance/benchmark/

[12]

調優指南: https://docs.cilium.io/en/latest/operations/performance/tuning/

[13]

cilium/cilium-perf-networking: https://github.com/cilium/cilium-perf-networking

[14]

Hubble: https://docs.cilium.io/en/latest/gettingstarted/hubble_setup/

[15]

Cilium 1.8 的發佈博客: https://cilium.io/blog/2020/06/22/cilium-18#kubeproxy-removal

[16]

Envoy 的 Socket 層重定向: https://cilium.io/blog/2018/08/07/istio-10-cilium#socket-level-redirection-to-accelerate-istio-and-envoy

[17]

Cilium Slack: https://cilium.io/slack

[18]

Twitter: https://twitter.com/ciliumproject

[19]

CNI 性能基準測試: https://docs.cilium.io/en/latest/operations/performance/benchmark/

[20]

調優指南: https://docs.cilium.io/en/latest/operations/performance/tuning/

[21]

Cilium 官方文檔: https://docs.cilium.io/en/latest/intro/

[22]

eBPF 官方網站: https://ebpf.io

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/-retfy8s8aa0n24v48rz4g