经典|Linux:为什么性能工具需要 BPF 技术(送多本)
了解更多BPF技術內幕,推薦閱讀《BPF之巔:洞悉Linux系統和應用性能》一書。
▼
BPF是近年來Linux 系統技術領域一個巨大的創新。作為 Linux 內核的一個關鍵發展節點,其重要程度不亞于虛擬化、容器、SDN 等技術。
▼BPF 的工作方式十分有趣 :
最終用戶使用 BPF 虛擬機的指令集(也稱 BPF 字節碼)定義過濾器表達式,然后傳遞給內核,由解釋器執行。這使得包過濾可以在內核中直接進行,避免了向用戶態進程復制每個數據包,從而提升了數據包過濾的性能,tcpdump(8) 就是這樣工作的。?
BPF 還提供了安全性保障,因為用戶定義的過濾器在執行前必須首先通過安全性驗證。
早期的包過濾必須在內核空間執行,安全是一個硬性要求。大家可以從下圖了解這一切是如何工作的。
tcpdump 和 BPF
在運行 tcpdump(8) 時帶上命令行參數 -d,可以打印出使用過濾器表達式的 BPF 指令。例如 :
▊ 經典 BPF 與擴展版?BPF
最初的 BPF 現在被稱為“經典 BPF”,它是一個功能有限的虛擬機。它有兩個寄存器,一個由 16 個內存槽位組成的臨時存儲區域和一個程序計數器。以上部件均按 32 位寄存器大小運行。經典 BPF 于 1997 年進入 Linux 內核版本 2.1.75。
而后Alexei Starovoitov 創造了擴展版 BPF(eBPF)。這是 20 年來 BPF 的第一次重大更新,此舉也將 BPF 擴展為一個通用的虛擬機。
雖然BPF通常被稱為虛擬機,不過這往往指的是它的實現規范。BPF在Linux中的實際實現(運行時支持)同時包括一個解釋器和一個可即時編譯為本機指令的編譯器。
“虛擬機”一詞似乎意味著在處理器之上運行另一個機器層,而實際BPF執行并非如此。JIT編譯后的代碼會像任何其他本地內核代碼一樣,直接在處理器上運行。要注意,在Spectre漏洞公布之后,一些發行版默認在x86架構上啟用JIT,完全移除了內核中的解釋器實現(通過條件編譯直接排除了相關代碼)。
擴展版的 BPF 中增加了更多寄存器,并將字長從 32 位增至 64 位,創建了靈活的BPF 映射型存儲(map),并允許調用一些受限制的內核功能。同時,eBPF 被設計為可以使用即時編譯(JIT),機器指令與寄存器可以一對一映射。這就使得先前的處理器本地指令優化技術,可以重用于 BPF 之上。BPF 驗證器也進行了更新以便支持這些擴展,而且能夠拒絕任何不安全的代碼。
經典 BPF 和擴展版 BPF 之間的差異如下。
在最早的代碼補丁中,擴展版BPF曾被簡寫為 eBPF,不過如今有關的開發討論中,都直接使用BPF 這種叫法。
Linux BPF 運行時(runtime)的各模塊的架構如下圖。
BPF 運行時的內部結構
上圖展示了 BPF 指令如何通過 BPF 驗證器驗證,再由 BPF 虛擬機執行。
BPF 虛擬機的實現既包括一個解釋器,又包括一個 JIT 編譯器 :JIT 編譯器負責生成處理器可直接執行的機器指令。驗證器會拒絕那些不安全的操作,這包括針對無界循環的檢查 :BPF 程序必須在有限的時間內完成。
BPF 可以利用輔助函數獲取內核狀態,利用 BPF 映射表進行存儲。BPF 程序在特定事件發生時執行,包括 kprobes、uprobes 和跟蹤點等事件。
接下來我們來討論一下,為什么性能工具需要 BPF 技術。
▊?為什么性能工具需要?BPF 技術
性能工具使用擴展版 BPF 來實現可編程性。BPF 程序可以執行自定義的延遲計算和統計摘要等功能。這些特性本身就足夠使 BPF 成為一個有趣的工具。
不過事實上有很多跟蹤工具都具備了這些功能。BPF 與眾不同之處在于,它還同時具備高效率和生產環境安全性的特點,并且它已經被內置在 Linux 內核中。
有了 BPF,你就可以在生產環境中直接運行這些工具,而無須增加新的內核組件。
▼
下面我們通過一個工具的輸出和一幅圖來看一下性能工具是如何使用 BPF 的。
這個 例子的輸出來自性能優化大師Gregg以前發布的一個叫作 bitehist 的 BPF 工具,它用直方圖的形式展示磁盤 I/O 的尺寸分布:
下圖顯示了使用 BPF 之前和之后的直方圖生成過程。
使用 BPF 之前和之后生成直方圖過程的對比
這里的關鍵變化是,直方圖可以在內核上下文中生成,這大大減少了需要復制到用戶空間的數據量。這里的效率提升是如此的顯著,以至于工具的額外開銷減小到可以在生產環境下直接運行的程度。
使用 BPF 之前,制作這一直方圖摘要的最佳步驟如下。
1.在內核中?:開啟磁盤 I/O 事件的插樁觀測。
2.在內核中,針對每個事件?:向 perf 緩沖區寫入一條記錄。如果使用了跟蹤點技術(推薦方式),記錄中會包含關于磁盤 I/O 的幾個元數據字段。
3.?在用戶空間?:周期性地將所有事件的緩沖區內容復制到用戶空間。
4.?在用戶空間?:遍歷每個事件,解析字節字段的事件元數據字段。其他字段會被忽略。
5.?在用戶空間?:生成字節字段的直方圖摘要
其中步驟?2?到步驟?4?對于高 I/O 的系統來說性能開銷非常大??梢韵胂笠幌?#xff0c;將 10000個磁盤 I/O 跟蹤記錄復制到用戶空間程序中,然后解析以生成摘要信息—每秒執行 1 次。
使用 BPF 之后,bitesize 程序執行的步驟如下。
1. 在內核中:啟用磁盤 I/O 事件的插樁觀測,并掛載一個由 bitesize 工具定義的BPF 程序。
2. 在內核中,對每次事件 :運行 BPF 程序。它只獲取字節字段,并將其保存到自定義的 BPF 直方圖映射數據結構中。
3.在用戶空間 :一次性讀取 BPF 直方圖映射表并輸出結果。
這個過程避免了將事件復制到用戶空間并再次對其處理的成本,也避免了對未使用的元數據字段的復制。如前面的程序輸出截圖所示,唯一需要復制到用戶空間的數據是“count”列,其是一個數字數組。
▊ BPF 與內核模塊的對比
還有一種方法可以理解 BPF 在可觀測性方面的優勢 :將其與內核模塊進行比較。
kprobes 和跟蹤點已經出現多年了,可以直接從可加載的內核模塊中使用。與使用內核模塊相比,使用 BPF 進行跟蹤的優勢如下 :
● BPF 程序會通過驗證器的安全性檢查 ;內核模塊則可能會引入 bug(內核崩潰)或安全漏洞。
● BPF 通過映射提供豐富的數據結構支持。
● BPF 程序可以一次編譯,然后在任何地方運行,因為 BPF 指令集、映射表結構、輔助函數和相關基礎設施屬于穩定的 ABI。(當然,有些 BPF 程序包含了不穩定的因素,比如使用了 kprobes 來觀測內核數據結構,這會影響 BPF 程序的自身穩定性)
●?BPF 程序的編譯不依賴內核編譯過程的中間結果。
●?與開發內核模塊所需的工程量相比,BPF 編程更加易學,可以讓更多人上手。
請注意,在網絡領域應用 BPF 還有額外的好處,包括原子性替換 BPF 程序的能力。如果使用內核模塊,則需要先從內核中將其完全卸載,然后再次加載,這可能會導致相關服務中斷。
使用內核模塊的一個好處是 :在模塊中可以使用其他內核函數和內核設施,而不僅限于 BPF 提供的輔助函數。
不過,如果調用任意內核函數的能力被濫用,也會帶來引入bug 的額外風險。
了解更多BPF技術內幕,推薦閱讀《BPF之巔:洞悉Linux系統和應用性能》一書。
▊《BPF之巔:洞悉Linux系統和應用性能》
【美】Brendan Gregg 著
孫宇聰 呂宏利 劉曉舟 譯
Gregg大師新作,《性能之巔》再續新篇
性能優化的萬用金典,150+分析調試工具深度剖析
本書作為全面介紹 BPF 技術的圖書,從 BPF 技術的起源到未來發展方向都有涵蓋,不僅全面介紹了 BPF 的編程模型,還完整介紹了兩個主要的 BPF 前端編程框架 — BCC 和 bpftrace,更給出了一系列實現范例,生動展示了 BPF技術的實際能力和未來發展前景。
(掃碼了解本書詳情)
京東雙11 活動?每滿100減50,建議湊單會非常劃算!
如果喜歡本書 歡迎?在看丨留言丨分享至朋友圈? 這本經典好書,我已經收入囊中,歡迎大家點贊留言,我這邊免費送三本給大家,送給有心人,歡迎大家三連支持,你們的支持才能持續送上經典好書,多謝了! 往期推薦: 實戰|QUIC協議在螞蟻集團落地豆瓣9.8分,周志明的《鳳凰架構》,高屋建瓴,推薦(送書)▼點擊閱讀原文,獲取本書詳情~
總結
以上是生活随笔為你收集整理的经典|Linux:为什么性能工具需要 BPF 技术(送多本)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何编写好的代码?
- 下一篇: 经典|图解Linux内存性能优化核心思想