【BPF入门系列-1】eBPF 技术简介
?
由范老師和我一起翻譯的圖書 《Linux內(nèi)核觀測技術(shù)BPF》 已經(jīng)在 JD 上有現(xiàn)貨,歡迎感興趣 BPF 技術(shù)的同學(xué)選購。鏈接地址?https://item.jd.com/72110825905.html
“eBPF 是我見過的 Linux 中最神奇的技術(shù),沒有之一,已成為 Linux 內(nèi)核中頂級子模塊,從 tcpdump 中用作網(wǎng)絡(luò)包過濾的經(jīng)典 cbpf,到成為通用 Linux 內(nèi)核技術(shù)的 eBPF,已經(jīng)完成華麗蛻變,為應(yīng)用與神奇的內(nèi)核打造了一座橋梁,在系統(tǒng)跟蹤、觀測、性能調(diào)優(yōu)、安全和網(wǎng)絡(luò)等領(lǐng)域發(fā)揮重要的角色。為 Service Mesh 打造了具備 API 感知和安全高效的容器網(wǎng)絡(luò)方案 Cilium,其底層正是基于 eBPF 技術(shù)”
1. BPF
BPF(Berkeley Packet Filter ),中文翻譯為伯克利包過濾器,是類 Unix 系統(tǒng)上數(shù)據(jù)鏈路層的一種原始接口,提供原始鏈路層封包的收發(fā)。1992 年,Steven McCanne 和 Van Jacobson 寫了一篇名為《BSD數(shù)據(jù)包過濾:一種新的用戶級包捕獲架構(gòu)》的論文。在文中,作者描述了他們?nèi)绾卧?Unix 內(nèi)核實現(xiàn)網(wǎng)絡(luò)數(shù)據(jù)包過濾,這種新的技術(shù)比當(dāng)時最先進的數(shù)據(jù)包過濾技術(shù)快 20 倍。BPF 在數(shù)據(jù)包過濾上引入了兩大革新:
- 
一個新的虛擬機 (VM) 設(shè)計,可以有效地工作在基于寄存器結(jié)構(gòu)的 CPU 之上; 
- 
應(yīng)用程序使用緩存只復(fù)制與過濾數(shù)據(jù)包相關(guān)的數(shù)據(jù),不會復(fù)制數(shù)據(jù)包的所有信息。這樣可以最大程度地減少BPF 處理的數(shù)據(jù); 
由于這些巨大的改進,所有的 Unix 系統(tǒng)都選擇采用 BPF 作為網(wǎng)絡(luò)數(shù)據(jù)包過濾技術(shù),直到今天,許多 Unix 內(nèi)核的派生系統(tǒng)中(包括 Linux 內(nèi)核)仍使用該實現(xiàn)。
tcpdump 的底層采用 BPF 作為底層包過濾技術(shù),我們可以在命令后面增加 ”-d“ 來查看 tcpdump 過濾條件的底層匯編指令。
| ? |  | 
圖 1-1 tcpdump 底層匯編指令
BPF 工作在內(nèi)核層,BPF 的架構(gòu)圖如下 [來自于bpf-usenix93]:
圖 1-2 tcpdump 運行架構(gòu)
2. eBPF
2.1 eBPF 介紹
2014 年初,Alexei Starovoitov 實現(xiàn)了 eBPF(extended Berkeley Packet Filter)。經(jīng)過重新設(shè)計,eBPF 演進為一個通用執(zhí)行引擎,可基于此開發(fā)性能分析工具、軟件定義網(wǎng)絡(luò)等諸多場景。eBPF 最早出現(xiàn)在 3.18 內(nèi)核中,此后原來的 BPF 就被稱為經(jīng)典 BPF,縮寫 cBPF(classic BPF),cBPF 現(xiàn)在已經(jīng)基本廢棄。現(xiàn)在,Linux 內(nèi)核只運行 eBPF,內(nèi)核會將加載的 cBPF 字節(jié)碼透明地轉(zhuǎn)換成 eBPF 再執(zhí)行。
eBPF 新的設(shè)計針對現(xiàn)代硬件進行了優(yōu)化,所以 eBPF 生成的指令集比舊的 BPF 解釋器生成的機器碼執(zhí)行得更快。擴展版本也增加了虛擬機中的寄存器數(shù)量,將原有的 2 個 32 位寄存器增加到 10 個 64 位寄存器。由于寄存器數(shù)量和寬度的增加,開發(fā)人員可以使用函數(shù)參數(shù)自由交換更多的信息,編寫更復(fù)雜的程序。總之,這些改進使 eBPF 版本的速度比原來的 BPF 提高了 4 倍。
| 維度 | cBPF | eBPF | 
|---|---|---|
| 內(nèi)核版本 | Linux 2.1.75(1997年) | Linux 3.18(2014年)[4.x for kprobe/uprobe/tracepoint/perf-event] | 
| 寄存器數(shù)目 | 2個:A, X | 10個: R0–R9, 另外 R10 是一個只讀的幀指針 | 
| 寄存器寬度 | 32位 | 64位 | 
| 存儲 | 16 個內(nèi)存位: M[0–15] | 512 字節(jié)堆棧,無限制大小的 “map” 存儲 | 
| 限制的內(nèi)核調(diào)用 | 非常有限,僅限于 JIT 特定 | 有限,通過 bpf_call 指令調(diào)用 | 
| 目標(biāo)事件 | 數(shù)據(jù)包、 seccomp-BPF | 數(shù)據(jù)包、內(nèi)核函數(shù)、用戶函數(shù)、跟蹤點 PMCs 等 | 
表格 1 cBPF 與 eBPF 對比
eBPF 在 Linux 3.18 版本以后引入,并不代表只能在內(nèi)核 3.18+ 版本上運行,低版本的內(nèi)核升級到最新也可以使用 eBPF 能力,只是可能部分功能受限,比如我就是在 Linux 發(fā)行版本 CentOS Linux release 7.7.1908 內(nèi)核版本 3.10.0-1062.9.1.el7.x86_64 上運行 eBPF 在生產(chǎn)環(huán)境上搜集和排查網(wǎng)絡(luò)問題。
eBPF 實現(xiàn)的最初目標(biāo)是優(yōu)化處理網(wǎng)絡(luò)過濾器的內(nèi)部 BPF 指令集。當(dāng)時,BPF 程序仍然限于內(nèi)核空間使用,只有少數(shù)用戶空間程序可以編寫內(nèi)核處理的 BPF 過濾器,例如:tcpdump和 seccomp。時至今日,這些程序仍基于舊的 BPF 解釋器生成字節(jié)碼,但內(nèi)核中會將這些指令轉(zhuǎn)換為高性能的內(nèi)部表示。
2014 年 6 月,eBPF 擴展到用戶空間,這也成為了 BPF 技術(shù)的轉(zhuǎn)折點。 正如 Alexei 在提交補丁的注釋中寫到:“這個補丁展示了 eBPF 的潛力”。當(dāng)前,eBPF 不再局限于網(wǎng)絡(luò)棧,已經(jīng)成為內(nèi)核頂級的子系統(tǒng)。eBPF 程序架構(gòu)強調(diào)安全性和穩(wěn)定性,看上去更像內(nèi)核模塊,但與內(nèi)核模塊不同,eBPF 程序不需要重新編譯內(nèi)核,并且可以確保 eBPF 程序運行完成,而不會造成系統(tǒng)的崩潰。
圖 2-1 BPF 架構(gòu)圖
簡述概括, eBPF 是一套通用執(zhí)行引擎,提供了可基于系統(tǒng)或程序事件高效安全執(zhí)行特定代碼的通用能力,通用能力的使用者不再局限于內(nèi)核開發(fā)者;eBPF 可由執(zhí)行字節(jié)碼指令、存儲對象和 Helper 幫助函數(shù)組成,字節(jié)碼指令在內(nèi)核執(zhí)行前必須通過 BPF 驗證器 Verfier 的驗證,同時在啟用 BPF JIT 模式的內(nèi)核中,會直接將字節(jié)碼指令轉(zhuǎn)成內(nèi)核可執(zhí)行的本地指令運行。
同時,eBPF 也逐漸在觀測(跟蹤、性能調(diào)優(yōu)等)、安全和網(wǎng)絡(luò)等領(lǐng)域發(fā)揮重要的角色。Facebook、NetFlix 、CloudFlare 等知名互聯(lián)網(wǎng)公司內(nèi)部廣泛采用基于 eBPF 技術(shù)的各種程序用于性能分析、排查問題、負載均衡、防范 DDoS 攻擊,據(jù)相關(guān)信息顯示在 Facebook 的機器上內(nèi)置一系列 eBPF 的相關(guān)工具。
相對于系統(tǒng)的性能分析和觀測,eBPF 技術(shù)在網(wǎng)絡(luò)技術(shù)中的表現(xiàn),更是讓人眼前一亮,BPF 技術(shù)與 XDP(eXpress Data Path) 和 TC(Traffic Control) 組合可以實現(xiàn)功能更加強大的網(wǎng)絡(luò)功能,更可為 SDN 軟件定義網(wǎng)絡(luò)提供基礎(chǔ)支撐。XDP 只作用與網(wǎng)絡(luò)包的 Ingress 層面,BPF 鉤子位于網(wǎng)絡(luò)驅(qū)動中盡可能早的位置,無需進行原始包的復(fù)制就可以實現(xiàn)最佳的數(shù)據(jù)包處理性能,掛載的 BPF 程序是運行過濾的理想選擇,可用于丟棄惡意或非預(yù)期的流量、進行 DDOS 攻擊保護等場景;而 TC Ingress 比 XDP 技術(shù)處于更高層次的位置,BPF 程序在 L3 層之前運行,可以訪問到與數(shù)據(jù)包相關(guān)的大部分元數(shù)據(jù),是本地節(jié)點處理的理想的地方,可以用于流量監(jiān)控或者 L3/L4 的端點策略控制,同時配合 TC egress 則可實現(xiàn)對于容器環(huán)境下更高維度和級別的網(wǎng)絡(luò)結(jié)構(gòu)。
圖 2-2 XDP 技術(shù)架構(gòu)
eBPF 相關(guān)的知名的開源項目包括但不限于以下:
- Facebook 高性能 4 層負載均衡器?Katran;
- Cilium?為下一代微服務(wù) ServiceMesh 打造了具備API感知和安全高效的容器網(wǎng)絡(luò)方案;底層主要使用 XDP 和 TC 等相關(guān)技術(shù);
- IO Visor 項目開源的?BCC、?BPFTrace?和?Kubectl-Trace:?BCC?提供了更高階的抽象,可以讓用戶采用 Python、C++ 和 Lua 等高級語言快速開發(fā) BPF 程序;BPFTrace?采用類似于 awk 語言快速編寫 eBPF 程序;Kubectl-Trace?則提供了在 kubernetes 集群中使用 BPF 程序調(diào)試的方便操作;
- CloudFlare 公司開源的?eBPF Exporter?和?bpf-tools:eBPF Exporter?將 eBPF 技術(shù)與監(jiān)控 Prometheus 緊密結(jié)合起來;bpf-tools?可用于網(wǎng)絡(luò)問題分析和排查;
越來越多的基于 eBPF 的項目如雨后脆筍一樣開始蓬勃發(fā)展,而且逐步在社區(qū)中異軍突起,成為一道風(fēng)景線。比如 IO Visor 項目的 BCC 工具,為性能分析和觀察提供了更加豐富的工具集:圖片來源
?
?
圖 2-3 Linux bcc/BPF 觀測工具
同時,IO Visor 的?bpf-docs?包含了日常的文檔,可以用于學(xué)習(xí)。
由于 eBPF 還在快速發(fā)展期,內(nèi)核中的功能也日趨增強,一般推薦基于Linux 4.4+ (4.9 以上會更好) 內(nèi)核的來使用 eBPF。部分 Linux Event 和 BPF 版本支持見下圖:
圖 2-4 Linux 事件和 BPF 版本支持
2.2 eBPF 架構(gòu)(觀測)
基于 Linux 系統(tǒng)的觀測工具中,eBPF 有著得天獨厚的優(yōu)勢,高效、生產(chǎn)安全且內(nèi)核中內(nèi)置,特別的可以在內(nèi)核中完成數(shù)據(jù)分析聚合比如直方圖,與將數(shù)據(jù)發(fā)送到用戶空間分析聚合相比,能夠節(jié)省大量的數(shù)據(jù)復(fù)制傳遞帶來的 CPU 消耗。
eBPF 整體結(jié)構(gòu)圖如下:
圖 2-5 eBPF 觀測架構(gòu)
eBPF 分為用戶空間程序和內(nèi)核程序兩部分:
- 用戶空間程序負責(zé)加載 BPF 字節(jié)碼至內(nèi)核,如需要也會負責(zé)讀取內(nèi)核回傳的統(tǒng)計信息或者事件詳情;
- 內(nèi)核中的 BPF 字節(jié)碼負責(zé)在內(nèi)核中執(zhí)行特定事件,如需要也會將執(zhí)行的結(jié)果通過 maps 或者 perf-event 事件發(fā)送至用戶空間;
其中用戶空間程序與內(nèi)核 BPF 字節(jié)碼程序可以使用 map 結(jié)構(gòu)實現(xiàn)雙向通信,這為內(nèi)核中運行的 BPF 字節(jié)碼程序提供了更加靈活的控制。
用戶空間程序與內(nèi)核中的 BPF 字節(jié)碼交互的流程主要如下:
- 我們可以使用 LLVM 或者 GCC 工具將編寫的 BPF 代碼程序編譯成 BPF 字節(jié)碼;
- 然后使用加載程序 Loader 將字節(jié)碼加載至內(nèi)核;內(nèi)核使用驗證器(verfier) 組件保證執(zhí)行字節(jié)碼的安全性,以避免對內(nèi)核造成災(zāi)難,在確認字節(jié)碼安全后將其加載對應(yīng)的內(nèi)核模塊執(zhí)行;BPF 觀測技術(shù)相關(guān)的程序程序類型可能是 kprobes/uprobes/tracepoint/perf_events 中的一個或多個,其中:
- kprobes:實現(xiàn)內(nèi)核中動態(tài)跟蹤。 kprobes 可以跟蹤到 Linux 內(nèi)核中的函數(shù)入口或返回點,但是不是穩(wěn)定 ABI 接口,可能會因為內(nèi)核版本變化導(dǎo)致,導(dǎo)致跟蹤失效。
- uprobes:用戶級別的動態(tài)跟蹤。與 kprobes 類似,只是跟蹤的函數(shù)為用戶程序中的函數(shù)。
- tracepoints:內(nèi)核中靜態(tài)跟蹤。tracepoints 是內(nèi)核開發(fā)人員維護的跟蹤點,能夠提供穩(wěn)定的 ABI 接口,但是由于是研發(fā)人員維護,數(shù)量和場景可能受限。
- perf_events:定時采樣和 PMC。
 
- 內(nèi)核中運行的 BPF 字節(jié)碼程序可以使用兩種方式將測量數(shù)據(jù)回傳至用戶空間
- maps?方式可用于將內(nèi)核中實現(xiàn)的統(tǒng)計摘要信息(比如測量延遲、堆棧信息)等回傳至用戶空間;
- perf-event?用于將內(nèi)核采集的事件實時發(fā)送至用戶空間,用戶空間程序?qū)崟r讀取分析;
 
如無特殊說明,本文中所說的 BPF 都是泛指 BPF 技術(shù)。
2.3 eBPF 的限制
eBPF 技術(shù)雖然強大,但是為了保證內(nèi)核的處理安全和及時響應(yīng),內(nèi)核中的 eBPF 技術(shù)也給予了諸多限制,當(dāng)然隨著技術(shù)的發(fā)展和演進,限制也在逐步放寬或者提供了對應(yīng)的解決方案。
- 
eBPF 程序不能調(diào)用任意的內(nèi)核參數(shù),只限于內(nèi)核模塊中列出的 BPF Helper 函數(shù),函數(shù)支持列表也隨著內(nèi)核的演進在不斷增加。(todo 添加個數(shù)說明) 
- 
eBPF 程序不允許包含無法到達的指令,防止加載無效代碼,延遲程序的終止。 
- 
eBPF 程序中循環(huán)次數(shù)限制且必須在有限時間內(nèi)結(jié)束,這主要是用來防止在 kprobes 中插入任意的循環(huán),導(dǎo)致鎖住整個系統(tǒng);解決辦法包括展開循環(huán),并為需要循環(huán)的常見用途添加輔助函數(shù)。Linux 5.3 在 BPF 中包含了對有界循環(huán)的支持,它有一個可驗證的運行時間上限。 
- 
eBPF 堆棧大小被限制在 MAX_BPF_STACK,截止到內(nèi)核 Linux 5.8 版本,被設(shè)置為 512;參見?include/linux/filter.h,這個限制特別是在棧上存儲多個字符串緩沖區(qū)時:一個char[256]緩沖區(qū)會消耗這個棧的一半。目前沒有計劃增加這個限制,解決方法是改用 bpf 映射存儲,它實際上是無限的。 /* BPF program can access up to 512 bytes of stack space. */ #define MAX_BPF_STACK 512
- 
eBPF 字節(jié)碼大小最初被限制為 4096 條指令,截止到內(nèi)核 Linux 5.8 版本, 當(dāng)前已將放寬至 100 萬指令( BPF_COMPLEXITY_LIMIT_INSNS),參見:include/linux/bpf.h,對于無權(quán)限的BPF程序,仍然保留4096條限制 ( BPF_MAXINSNS );新版本的 eBPF 也支持了多個 eBPF 程序級聯(lián)調(diào)用,雖然傳遞信息存在某些限制,但是可以通過組合實現(xiàn)更加強大的功能。 #define BPF_COMPLEXITY_LIMIT_INSNS 1000000 /* yes. 1M insns */
2.4 eBPF 與內(nèi)核模塊對比
在 Linux 觀測方面,eBPF 總是會拿來與 kernel 模塊方式進行對比,eBPF 在安全性、入門門檻上比內(nèi)核模塊都有優(yōu)勢,這兩點在觀測場景下對于用戶來講尤其重要。
| 維度 | Linux 內(nèi)核模塊 | eBPF | 
|---|---|---|
| kprobes/tracepoints | 支持 | 支持 | 
| 安全性 | 可能引入安全漏洞或?qū)е聝?nèi)核 Panic | 通過驗證器進行檢查,可以保障內(nèi)核安全 | 
| 內(nèi)核函數(shù) | 可以調(diào)用內(nèi)核函數(shù) | 只能通過 BPF Helper 函數(shù)調(diào)用 | 
| 編譯性 | 需要編譯內(nèi)核 | 不需要編譯內(nèi)核,引入頭文件即可 | 
| 運行 | 基于相同內(nèi)核運行 | 基于穩(wěn)定 ABI 的 BPF 程序可以編譯一次,各處運行 | 
| 與應(yīng)用程序交互 | 打印日志或文件 | 通過 perf_event 或 map 結(jié)構(gòu) | 
| 數(shù)據(jù)結(jié)構(gòu)豐富性 | 一般 | 豐富 | 
| 入門門檻 | 高 | 低 | 
| 升級 | 需要卸載和加載,可能導(dǎo)致處理流程中斷 | 原子替換升級,不會造成處理流程中斷 | 
| 內(nèi)核內(nèi)置 | 視情況而定 | 內(nèi)核內(nèi)置支持 | 
表格 2 eBPF 與 Linux 內(nèi)核模塊方式對比
3. 應(yīng)用案例
大名鼎鼎的性能分析大師 Brendan Gregg 等編寫了諸多的 BCC 或 BPFTrace 的工具集可以拿來直接使用,完全可以滿足我們?nèi)粘栴}分析和排查。
BCC 在 CentOS 7 系統(tǒng)中可以通過 yum 快速安裝
|  | 
其他系統(tǒng)的安裝方式參見:INSTALL.md
BCC 中每一個工具都有一個對應(yīng)的使用樣例,比如?execsnoop.py?和?execsnoop_example.txt,在使用樣例中有詳細的使用說明,而且 BCC 中的工具使用的幫助文檔格式基本類似,上手非常方便。
BCC 的程序一般情況下都需要 root 用戶來運行。
3.1 Linux 性能分析 60 秒 (BPF版本)
英文原文?Linux Performance Analysis in 60,000 Milliseconds,視頻地址
|  | 
60s 系列 BPF 版本如下:
圖 3-1 60s 排查之 BPF 版本
對于在系統(tǒng)中運行的 “閃電俠” 程序,運行周期非常短,但是可能會帶來系統(tǒng)的抖動延時,我們采用?top?命令查看一般情況下難以發(fā)現(xiàn),我們可以使用 BCC 提供的工具?execsnoop?來進行排查:
|  | 
3.2?slab dentry 過大導(dǎo)致的網(wǎng)絡(luò)抖動排查
現(xiàn)象
網(wǎng)絡(luò) ping 的延時間歇性有規(guī)律出現(xiàn)抖動
問題排查
采用?execsnoop?分析發(fā)現(xiàn),某個運行命令cat /proc/slabinfo的運行時間間隔與抖動的頻率完全吻合,順著這個的線索定位,我們發(fā)現(xiàn)云廠商提供的 Java 版本的云監(jiān)控會定期調(diào)用?cat /proc/slabinfo?來獲取內(nèi)核緩存的信息;
通過命令?slabtop?發(fā)現(xiàn)系統(tǒng)中的?dentry?項的內(nèi)存占用非常大,系統(tǒng)內(nèi)存 128G,dentry?占用 70G 以上,所以問題很快就定位到是系統(tǒng)在打開文件方面可能有相關(guān)問題;
根因分析
我們使用對于打開文件跟蹤的 BCC 工具?opensnoop?很快就定位到是某個程序頻繁創(chuàng)建和刪除臨時文件,最終定位為某個 PHP 程序設(shè)置的調(diào)用方式存在問題,導(dǎo)致每次請求會創(chuàng)建和刪除臨時文件;代碼中將 http 調(diào)用中的?contentType?設(shè)置成了?Http::CONTENT_TYPE_UPLOAD,導(dǎo)致每次請求都會生成臨時文件,修改成?application/x-www-form-urlencoded?問題解決。
問題的原理可參考?記一次對網(wǎng)絡(luò)抖動經(jīng)典案例的分析?和?systemtap腳本分析系統(tǒng)中dentry SLAB占用過高問題
3.3 生成火焰圖
火焰圖是幫助我們對系統(tǒng)耗時進行可視化的圖表,能夠?qū)Τ绦蛑心切┐a經(jīng)常被執(zhí)行給出一個清晰的展現(xiàn)。Brendan Gregg 是火焰圖的創(chuàng)建者,他在?GitHub?上維護了一組腳本可以輕松生成需要的可視化格式數(shù)據(jù)。使用 BCC 中的工具?profile?可很方面地收集道 CPU 路徑的數(shù)據(jù),基于數(shù)據(jù)采用工具可以輕松地生成火焰圖,查找到程序的性能瓶頸。
使用?
profile?搜集火焰圖的程序沒有任何限制和改造
profile?工具可以讓我們輕松對于系統(tǒng)或者程序的 CPU 性能路徑進行可視化分析:
/usr/share/bcc/tools/profile -h
usage: profile [-h] [-p PID | -L TID] [-U | -K] [-F FREQUENCY | -c COUNT] [-d][-a] [-I] [-f] [--stack-storage-size STACK_STORAGE_SIZE][-C CPU][duration]Profile CPU stack traces at a timed intervalpositional arguments:duration              duration of trace, in secondsoptional arguments:-h, --help            show this help message and exit-p PID, --pid PID     profile process with this PID only-L TID, --tid TID     profile thread with this TID only-U, --user-stacks-onlyshow stacks from user space only (no kernel spacestacks)-K, --kernel-stacks-onlyshow stacks from kernel space only (no user spacestacks)-F FREQUENCY, --frequency FREQUENCYsample frequency, Hertz-c COUNT, --count COUNTsample period, number of events-d, --delimited       insert delimiter between kernel/user stacks-a, --annotations     add _[k] annotations to kernel frames-I, --include-idle    include CPU idle stacks-f, --folded          output folded format, one line per stack (for flamegraphs)--stack-storage-size STACK_STORAGE_SIZEthe number of unique stack traces that can be storedand displayed (default 16384)-C CPU, --cpu CPU     cpu number to run profile onexamples:./profile             # profile stack traces at 49 Hertz until Ctrl-C./profile -F 99       # profile stack traces at 99 Hertz./profile -c 1000000  # profile stack traces every 1 in a million events./profile 5           # profile at 49 Hertz for 5 seconds only./profile -f 5        # output in folded format for flame graphs./profile -p 185      # only profile process with PID 185./profile -L 185      # only profile thread with TID 185./profile -U          # only show user space stacks (no kernel)./profile -K          # only show kernel space stacks (no user)
profile?配合?FlameGraph?可以輕松幫我們繪制出 CPU 使用的火焰圖。
|  | 
圖 3-2 火焰圖
3.3 排查網(wǎng)絡(luò)調(diào)用來源
在生產(chǎn)場景下,會有些特定場景需要抓取連接到外網(wǎng)特定地址的程序,這時候我們可以采用 BCC 工具集中的?tcplife?來定位。
/usr/share/bcc/tools/tcplife -h
usage: tcplife [-h] [-T] [-t] [-w] [-s] [-p PID] [-L LOCALPORT][-D REMOTEPORT]Trace the lifespan of TCP sessions and summarizeoptional arguments:-h, --help            show this help message and exit-T, --time            include time column on output (HH:MM:SS)-t, --timestamp       include timestamp on output (seconds)-w, --wide            wide column output (fits IPv6 addresses)-s, --csv             comma separated values output-p PID, --pid PID     trace this PID only-L LOCALPORT, --localport LOCALPORTcomma-separated list of local ports to trace.-D REMOTEPORT, --remoteport REMOTEPORTcomma-separated list of remote ports to trace.examples:./tcplife           # trace all TCP connect()s./tcplife -t        # include time column (HH:MM:SS)./tcplife -w        # wider colums (fit IPv6)./tcplife -stT      # csv output, with times & timestamps./tcplife -p 181    # only trace PID 181./tcplife -L 80     # only trace local port 80./tcplife -L 80,81  # only trace local ports 80 and 81./tcplife -D 80     # only trace remote port 80
通過在機器上使用?tcplife?來獲取的網(wǎng)絡(luò)連接信息,我們可以看到包括了 PID、COMM、本地 IP 地址、本地端口、遠程 IP 地址和遠程端口,通過這些信息非常方便排查到連接到特定 IP 地址的程序,尤其是連接的過程非常短暫,通過?netstat?等其他工具不容易排查的場景。
|  | 
如果我們想知道更加詳細的 TCP 狀態(tài)情況,那么?tcptracer?可展示更加詳細的 TCP 狀態(tài),其中 C 代表 Connect X 表示關(guān)閉, A 代表 Accept。
|  | 
tcpstates?還能夠展示出來 TCP 狀態(tài)機的流轉(zhuǎn)情況:
|  | 
同樣,我們也可以實時獲取到 TCP 連接超時或者重連的網(wǎng)絡(luò)連接;也可以通過抓取 UDP包相關(guān)的連接信息,用于定位諸如 DNS 請求超時或者 DNS 請求的發(fā)起進程。
4. 編寫 BPF 程序
對于大多數(shù)開發(fā)者而言,更多的是基于 BPF 技術(shù)之上編寫解決我們?nèi)粘S龅降母鞣N問題,當(dāng)前 BCC 和 BPFTrace 兩個項目在觀測和性能分析上已經(jīng)有了諸多靈活且功能強大的工具箱,完全可以滿足我們?nèi)粘J褂谩?/p>
- BCC?提供了更高階的抽象,可以讓用戶采用 Python、C++ 和 Lua 等高級語言快速開發(fā) BPF 程序;
- BPFTrace?采用類似于 awk 語言快速編寫 eBPF 程序;
更早期的工具則是使用 C 語言來編寫 BPF 程序,使用 LLVM clang 編譯成 BPF 代碼,這對于普通使用者上手有不少門檻當(dāng)前僅限于對于 eBPF 技術(shù)更加深入的學(xué)習(xí)場景。
4.1 BCC 版本 HelloWorld
圖 4-1 BCC 整體架構(gòu)
使用 BCC 前端綁定語言 Python 編寫的 Hello World 版本:
#!/usr/bin/python3from bcc import BPF# This may not work for 4.17 on x64, you need replace kprobe__sys_clone with kprobe____x64_sys_clone
prog = """int kprobe__sys_clone(void *ctx) {bpf_trace_printk("Hello, World!\\n");return 0;}
"""b = BPF(text=prog, debug=0x04)
b.trace_print()
運行程序前需要安裝過 bcc 相關(guān)工具包,當(dāng)運行正常的時候我們發(fā)現(xiàn)每當(dāng)?sys_clone?系統(tǒng)調(diào)用時,運行的控制臺上就會打印 “Hello, World!”,在打印文字前面還包含了調(diào)用程序的進程名稱,進程 ID 等信息;
如果運行報錯,可能是缺少頭文件,一般安裝 kernel-devel 包即可。
# python ./hello.pykubelet-8349  [006] d... 33637334.829981: : Hello, World!kubelet-8349  [006] d... 33637334.838594: : Hello, World!kubelet-8349  [006] d... 33637334.843788: : Hello, World!
4.3 BPFTrace
BPFTrace 是基于 BPF 和 BCC 的開源項目,與 BCC 不同的是其提供了更高層次的抽象,可以使用類似 AWK 腳本語言來編寫基于 BPF 的跟蹤或者性能排查工具,更加易于入門和編寫,該工具的主要靈感來自于 Solaris 的 D 語言。BPFTrace 更方便與編寫單行的程序。BPFTrace 與 BCC 一樣也是 IO Visor 組織下的項目,倉庫參見?bpftrace。更加深入的學(xué)習(xí)資料參見:Reference Guide?和?One-Liner Tutorial。
BPFTrace 使用 LLVM 將腳本編譯成 BPF 二進制碼,后續(xù)使用 BCC 與 Linux 內(nèi)核進行交互。從功能層面上講,BPFTrace 的定制性和靈活性不如 BCC,但是比 BCC 工具更加易于理解和使用,降低了 BPF 技術(shù)的使用門檻。
使用樣例:
|  | 
4.3 C 語言原生方式
采用 LLVM Clang 的方式編譯會涉及到內(nèi)核編譯環(huán)境搭建,而且還需要自己編譯 Makefile 等操作,屬于高級用戶使用:
bpf_program.c
|  | 
loader.c
|  | 
Makefile 文件(部分)
|  | 
其中 clang 編譯中的選型?-target bpf?表明我們將代碼編譯成 bpf 的字節(jié)碼。
完整的程序參見:hello_world;更多的樣例代碼可以參見對應(yīng)內(nèi)核中?kernel-src/samples/bpf/?下的樣例代碼。
5. 國內(nèi)大廠 eBPF 實踐經(jīng)驗
- 
eBPF 在網(wǎng)易輕舟云原生的應(yīng)用實踐 
- 
性能提升40%: 騰訊 TKE 用 eBPF繞過 conntrack 優(yōu)化K8s Service 
- 
字節(jié)跳動:eBPF 技術(shù)實踐:高性能 ACL 
- 
阿里:eBPF Internal:Instructions and Runtime 
- 
使用 ebpf 深入分析容器網(wǎng)絡(luò) dup 包問題 
- 
eBay 云計算“網(wǎng)”事:網(wǎng)絡(luò)超時篇?eBay云計算“網(wǎng)”事|網(wǎng)絡(luò)丟包篇 
- 
字節(jié)跳動容器化場景下的性能優(yōu)化實踐 
6. 參考資料
- 
The BSD Packet Filter: A New Architecture for User-level Packet Capture 
- 
[譯] Cilium:BPF 和 XDP 參考指南(2019)?Cillum BPF and XDP Reference Guide 
- 
Cloudflare架構(gòu)以及BPF如何占據(jù)世界 
- 
關(guān)於 BPF 和 eBPF 的筆記 
- 
Dive into BPF: a list of reading material?中文 
- 
eBPF 簡史 
- 
https://www.youtube.com/watch?v=znBGt7oHJyQ 
- 
BPF Documentation?HOWTO interact with BPF subsystem 
- 
Linux 內(nèi)核 BPF 文檔 
- 
Linux Extended BPF (eBPF) Tracing Tools?Brendan Gregg 
- 
性能提升40%: 騰訊 TKE 用 eBPF繞過 conntrack 優(yōu)化K8s Service 
- 
SDN handbook 
- 
Linux BPF 幫助文檔?bpf(2)?bpf-helpers(7)?tc-bpf(8) - 
user commands 
- 
system calls 
- 
library functions 
- 
special files 
- 
file formats and filesystems 
- 
games 
- 
overview and miscellany section 
- 
administration and privileged commands 
 參考:https://man7.org/linux/man-pages/index.html 
- 
- 原文作者:DavidDi
- 原文鏈接:https://www.ebpf.top/post/ebpf_intro/
- 版權(quán)聲明:本作品采用知識共享署名-非商業(yè)性使用-禁止演繹 4.0 國際許可協(xié)議進行許可,非商業(yè)轉(zhuǎn)載請注明出處(作者,原文鏈接),商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)。
總結(jié)
以上是生活随笔為你收集整理的【BPF入门系列-1】eBPF 技术简介的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 【学习周报】
- 下一篇: 最新安卓手机好评率排名公布 小米手机进不
