在 CNCF 的 Observability Whitepaper 中,除了大家耳熟能詳的 Metrics、Logs 和 Traces,也提到了 Profiles 和 Dumps 這兩種 Observability Signals。這兩者具有下列功能:
在這篇文章中,我們將會介紹 Profiles 以及和它有點關係的 eBPF,並介紹對應的兩個開源專案:Grafana Pyroscope 與 Grafana Beyla。
掌握了多種 Observability 工具後,要找出微服務架構中的效能瓶頸應當不難。然而,若要深入了解是哪一行程式碼、哪個函數或物件導致效能瓶頸,就需使用 Profiles。這種測量程式效能的行為稱作 Profiling,而進行 Profiling 的工具則稱為 Profiler。
各種程式語言都有相對應的 Profiler。例如,在 Python 中,可用 cProfile 來紀錄執行細節,並配合 SnakeViz 進行視覺化。Java 則可參考 Baeldung 的 A Guide to Java Profilers 文章,其中列出了多種 Profiler。
使用 SnakeViz 檢視程式碼執行時間佔比,圖片來源:SnakeViz
傳統上,Profiler 主要用於開發階段,以測試資料確認問題。在生產環境中較少使用,因為持續資料採集會消耗大量資源,影響服務效能。但隨著技術的推進,消耗資源的問題透過新的技術能夠減輕,於是有愈來愈多工具能在生產環境中持續進行 Profiling,所以又稱之為 Continuous Profiling。
2023 年 3 月,Grafana Labs 收購了 Pyroscope。這個工具可以監測 CPU 和記憶體的使用情況,並透過火焰圖 Flame Graph 進行視覺化。這讓開發者能快速了解程式效能並進行優化。Pyroscope 提供了兩種資料收集方式:
使用 SDK 和 eBPF 的差別主要在於,前者允許更高度的客製化但需要調整程式碼,後者則無需改動程式碼,但需要特定版本的 Linux Kernel。具體比較請參見 Pros and cons of eBPF and non-eBPF profiling。
目前,Pyroscope 對 Go 語言的支援較為完善,包括 CPU、Memory 和 goroutine 等資訊。其他語言,如 Java 和 Python,則僅能收集 CPU 資訊,但預計未來會有更多的支援。
eBPF(Extended Berkeley Packet Filter)是一個在 Linux Kernel 中執行程式的機制。這些 eBPF 程式能綁定到核心裡的特定 hook point,使得它們在特定事件發生時被觸發。例如,當網路封包到達或是硬體資源被存取時,相關的 eBPF 程式會執行,以收集或處理這些活動的資訊。由於它們運作於核心層面,因此能高效地獲取系統底層資訊。此外,這些程式會經過嚴格的安全檢查,以確保不會對系統造成危害。儘管 eBPF 起初只是 BPF(用於網路封包過濾的 Berkeley Packet Filter)的擴充版本,但其功能和應用範圍已經遠超過原始的 BPF,因此現在 eBPF 也被視為一項獨立的技術,而不再只是 BPF 的延伸。
eBPF Hook 範例,圖片來源:eBPF.io
eBPF 於 2014 年由 Plumgrid(於 2016 年被 VMware 收購)的工程師 Alexei Starovoitov 開發了初始的版本,Plumgrid 的工程師們希望可以有更簡單有效的方式監控 SDN(Software-Defined Network)中的網路流量,於是發展出了 eBPF。多年來,社群的積極推動使得相關開源專案蓬勃發展,而多家公司也已開始在生產環境中採用 eBPF,其應用的價值已被廣泛認可。eBPF Foundation 也在 2021 年 8 月建立,創始成員為 Meta、Google、Isovalent、Microsoft、Netflix。
eBPF 的其他應用範例包括:
更多關於 eBPF 的專案和應用案例,可參考 eBPF.io 的 Project Landscape 和 Case Studies。
Grafana 的開源專案 Beyla 也使用 eBPF 監控應用程式和 Linux OS。它能收集經由 HTTP、HTTPS、gRPC 傳送的資訊,並生成 Metrics 和 Traces。
透過 Prometheus 收集的 Metrics 可以用 Grafana 進行視覺化建立 RED Metrics Dashboard,如下:
圖片來源:Beyla RED Metrics
這些資料收集工作完全是利用 eBPF 完成的,不需要修改任何程式碼或添加額外的 Instrumentation,因此被視為一種無侵入式的資料收集方式。
範例程式碼:25-profiles-and-ebpf
啟動所有服務
docker-compose up -d
檢視服務
FastAPI App: http://localhost:8000
Spring Boot App: http://localhost:8080
使用 k6 發送 Request
k6 run --vus 1 --duration 300s k6-script.js
Pyroscope: http://localhost:4040
Grafana: http://localhost:3000,登入帳號密碼為 admin/admin
Pyroscope
process_cpu - cpu
,查詢語法輸入
{service_name="fastapi"}
可以查看 FastAPI App 使用 SDK 取得的 CPU Profile{service_name="spring-boot"}
可以查看 Spring Boot App 使用 SDK 取得的 CPU Profile{service_name="compose-example"}
可以查看 Grafana Agent 透過 eBPF 取得的所有 Container CPU Profile{service_name="pyroscope"}
可以查看 Pyroscope 服務本身的 CPU Profile關閉所有服務
docker-compose down
軟體工程師對於系統掌控的渴望如深淵般無底。從過去傳統的單體式架構的 Profiling,到微服務架構的 Distributing Tracing,再到 eBPF 的出現,技術的演進讓我們能更深入地了解系統運作的每一個細節。這也是本文標題借用 eBPF 紀錄片的名稱「eBPF: UNLOCKING THE KERNEL」的原因。只要能深入了解核心運作,就能更有效地掌控和優化系統,無論是 Profiles 還是其他 Observability Signals,一切都能掌握在手中。