【譯】何時(以及何時不)使用 eBPF
原文地址:https://www.tigera.io/blog/ebpf-when-and-when-not-to-use-it/
本文介紹了 eBPF 的一些基本應用場景,主要和內核函數,iptables 對比,讓大家能理解 eBPF 應該在那些場景下使用,那些場景下不建議使用。我認爲可以作爲入門 eBPF 的必修課,學習一個技術,必須知道這個技術擅長那些場景,不擅長那些場景,在學習和使用上纔不至於走彎路。
前言
擴展伯克利包過濾器 (eBPF) 是 Linux 內核的一個相對較新的特性,這個特性讓許多 DevOps、SRE 和工程師感到眼前一亮。但是它是滿足所有 Linux 內核需求的一站式解決方案嗎?所以本文中我們要分析看看 eBPF 在哪些方面做得很好,以及它與標準 Linux iptables 的對比如何。
eBPF 是什麼?
eBPF 是 Linux 內核中一個已經可用的特性,它允許在內核中運行一個虛擬機。這個虛擬機可以讓你安全地將程序加載到內核中並執行,這樣就可以靈活的在用戶層定義各種內核中的操作了。那爲什麼這很重要呢?
在過去,對內核進行功能更改是非常困難的:可以調用一些內核 api 來獲取數據,但不能影響內核內部的內容或執行代碼。如果要這樣做,那你需要向 Linux 社區提交一個補丁,然後等待它被批准。而使用 eBPF,可以將程序加載到內核中,並讓內核在一些情況下執行你的程序,比如收到一個數據包或者其他的事件發生。
有了 eBPF,內核及其行爲變得高度可定製,不再是固定的了。如果在合適的情況下使用這種能力,將是非常有價值的。
如何使用 eBPF?
eBPF 有幾個使用場景,包括流量控制、創建網絡策略、連接時長負載平衡和可觀察性。
流量控制
如果沒有 eBPF,數據包使用標準的 Linux 網絡路徑到達最終目的地。如果一個數據包出現在 A 點,並且你知道這個數據包需要到達 B 點,那麼你可以通過優化 Linux 內核中的網絡路徑將數據包直接發送到 B 點來。使用 eBPF,你就可以利用額外的上下文在內核中進行這些更改,這樣數據包就可以繞過複雜的路由,直接到達最終目的地。
這在 Kubernetes 容器環境中尤其有用,因爲其中有許多網絡。(除了主機網絡堆棧,每個容器都有自己的迷你網絡堆棧)當流量進來時,它通常被路由到一個容器堆棧,並且在從主機堆棧到達那裏的過程中必須經過一個複雜的路徑。可以使用 eBPF 繞過此複雜的路由。
創建網絡策略
在創建網絡策略時,有兩種情況可以使用 eBPF:
-
eXpress 數據路徑 (XDP) - 當一個原始數據包緩衝區進入系統時,eBPF 爲你提供了一種有效的方法來檢查該緩衝區並快速決定如何處理它。
-
網絡策略 - eBPF 允許高效地檢查數據包和實施網絡策略,無論是 pod 和主機。
連接時長負載平衡
在 Kubernetes 中進行負載均衡服務連接時,一個端口需要與服務進行通信,因此需要進行 NAT 轉換。一個數據包被髮送到一個虛擬 IP,該虛擬 IP 將其轉換爲目的 IP 是支持該服務的 pod 上;然後 pod 響應虛擬 IP,返回的數據包被轉發回源地址。
通過使用 eBPF,可以使用已加載到內核的 eBPF 程序在連接開始處理的地方進行負載平衡,從而避免這種包轉換。由於目的網絡地址轉換(DNAT)不需要在包處理路徑上做處理,因此所有來自服務連接的 NAT 開銷都被優化掉了。
可觀察性
使用 eBPF 實現可觀察性的兩種有用方法:收集統計信息和深入調試內核。eBPF 程序可以附加到內核中許多不同的函數上,可以訪問這些函數正在處理的數據,也允許修改這些數據。例如,使用 eBPF,如果建立了網絡連接,則可以在創建套接字時觸發一個調用。爲什麼將套接字調用作爲事件接收很重要?因爲 eBPF 在打開套接字的程序的上下文中提供了這些函數調用,因此可以獲得關於哪個進程打開了它,以及套接字發生了什麼事情。
性能的代價
那麼 eBPF 比標準的 Linux iptables 更有效嗎?簡單來說:要分情況來看。
如果要對 iptables 在大量 IP 地址 (即 ipset) 的進行網絡策略時的工作方式進行微基準測試,iptables 在很多情況下比 eBPF 更好。但是如果想在 Linux 內核中做一些事情,比如需要更改內核中的數據包流向,那麼 eBPF 將是更好的選擇。標準的 Linux iptables 是一個複雜的系統,當然有它的侷限性,但同時它提供了操控流量的能力;如果你知道如何編寫 iptables 規則,那麼你可以做很多事情。eBPF 允許將自己的程序加載到內核中,並可以根據你的需要定製影響內核中的行爲,因此它比 iptables 更靈活,因爲它不侷限於是一組規則。
另外需要考慮的是,雖然 eBPF 允許運行程序、添加邏輯、重定向流向和繞過處理 (這是肯定的優勢),但它是一個虛擬機,因此必須轉換爲字節碼運行。相比之下,Linux 內核的 iptables 運行的是已經編譯好的代碼。
正如你所看到的,eBPF 和 iptables 並不是一個直接的比較。我們需要評估的是性能,這裏需要關注的兩個關鍵因素是延遲(速度)和消耗。如果 eBPF 非常快,但佔用了 80% 的資源,那麼它就像蘭博基尼——一輛昂貴的跑車。如果這對你有用,那太好了 (也許你真的喜歡昂貴的跑車)。只要記住,更多的 CPU 使用就意味着你要在雲提供商這裏花更多的錢。因此,雖然蘭博基尼可能比很多其他汽車都快,但如果你需要遵守日常通勤的速度限制,它可能不是最好的花錢方式。
何時使用 eBPF(何時不使用)
使用 eBPF,你可以獲得性能——但這是有代價的。你需要通過計算性能的代價,並從 eBPF 的功能角度決定你是否接受,要從而找到兩者之間的平衡。
來看一些使用 eBPF 有意義的具體情況,以及一些不建議使用 eBPF 的情況。
✘ 何時不用 eBPF
-
實現應用層策略 - 由於價格與性能的權衡,使用 eBPF 執行深度協議檢查和實現應用層策略的效率不是很高。你可以利用 Linux 內核的連接跟蹤器( connection tracker)來實現策略,對每個流應用一次策略(無論流有 5 個包還是 5000 個包),並在 Linux conntrack 表中將其標記爲允許或拒絕。不需要不斷檢查流中的每個包。如果要使用 eBPF 實現策略,它允許在單個 TCP 連接上有多個 HTTP 事務,爲了檢測這些事務需要檢查每個包,並且要實現第 7 層控制。要做到這一點,需要執行 CPU 週期,這個代價非常大。一種更有效的方法是使用像 Envoy 這樣的代理,並使用 eBPF 優化到 Envoy 的流量,同時讓 Envoy 爲來翻譯應用程序協議。Iptables + Envoy 這樣的代理是更好的設計,在這種情況下也是更好的選擇。
-
構建服務網格控制平面 - 類似地,服務網格依賴於像 Envoy 這樣的代理。多年來,我們在設計這一過程上花了很多心思。這樣做的主要原因是,在許多情況下,對於像 HTTP 這樣的應用協議,在集羣內高速進行內置處理是不可行的。因此,應該考慮使用 eBPF 以一種有效的方式將通信路由到像 Envoy 這樣的代理,而不是使用它替換代理本身。
-
逐包處理 — 使用 eBPF 執行 CPU 密集型或逐包處理,例如對加密流進行解密和重新加密,並不高效,因爲需要構建一個結構並對每個包進行查找,代價非常大。
✔ When to use eBPF
-
XDP - eBPF 在原始數據包進入系統時提供了一種有效的處理方法,允許快速決定如何處理數據包。
-
連接時間負載平衡 - 使用 eBPF 可以在源端使用加載到內核的程序進行負載平衡,而不是使用虛擬 IP。由於 DNAT 不需要發生在包處理路徑上,所有來自業務連接的 NAT 開銷就都被優化了。
-
可觀察性 - epf 程序是在 Linux 內核中添加探測器作爲傳感器的極好方法,以獲得上下文豐富的數據。這是一個巨大的好處,因爲不需要更改內核來支持跟蹤和分析。您可以很容易地在打開套接字的程序的上下文中接收套接字調用,或者添加程序來跟蹤內核中的系統調用。在我們看來,可觀察性是 eBPF 最有用的用例。
總結
eBPF 是 iptables 的替代品嗎?我想不完全是。很難想象所有東西在 eBPF 中都能像在 iptables 中一樣高效地工作。目前,這兩種功能是共存的,取決於用戶如何權衡代價和性能,並根據他們的特定需求決定何時使用哪個功能。
我們相信正確的解決方案是利用 eBPF 加上 Linux 內核中的現有機制來實現你想要的結果。既然我們已經確定 eBPF 和 iptables 都是有用的,那麼在我們看來,唯一符合邏輯的事情就是同時支持兩者。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/gsohsQNXO7p7NMLkCDaaow