博客 / 詳情

返回

eBPF + OpenTelemetry:適用於任何應用的零代碼自動化儀表盤

本文介紹如何將 eBPF 與 OpenTelemetry 結合,實現自動化、零代碼的分佈式追蹤和可觀測性系統,瞭解 Odigos、Beyla 和 OpenTelemetry eBPF 等工具的工作原理、適用場景以及如何在生產環境中設置。原文:Using eBPF with OpenTelemetry: Zero-Code Auto-Instrumentation for Any Application

如果能在所有服務間實現完整的分佈式追蹤,而無需添加一行儀表盤代碼,怎麼樣?

傳統 OpenTelemetry 儀表盤需要添加 SDK、配置導出器,並用 span 包裝代碼。雖然功能強大,但需要付出不少努力,尤其是系統中有數十種不同語言的服務時。

eBPF 完全改變了這一模式。通過從 Linux 內核觀察應用,基於 eBPF 的工具可以自動生成兼容 OpenTelemetry 的追蹤、指標和配置文件,而無需觸及應用代碼 。

本文將介紹如何將 eBPF 與 OpenTelemetry 結合,實現強大的零代碼可觀測性。


1. 問題:大規模儀表盤

傳統 OpenTelemetry 儀表盤遵循以下模式:

  1. 為每個服務添加 OTel SDK
  2. 配置導出器
  3. 測量入口點(HTTP 處理程序,gRPC 方法)
  4. 為重要操作添加 span
  5. 跨服務邊界傳播上下文
  6. 每個服務、每種語言都要重複

對於只有少量服務的小團隊來説,還算可以管理。但請考慮:

|場景|挑戰|
|-|-|
| 50+ 微服務|需要數週時間集成跨所有服務的 SDK|
|多語言技術棧|Go、Python、Node.js、Java、Rust 等不同的 SDK……|
|遺留服務|代碼不容易修改,沒人願意碰|
|第三方服務|無法訪問源代碼|
|快速部署|新服務出現的速度比測量它們的速度還快|

結果呢?可觀測性缺口。有些服務有追蹤,有些沒有。未安裝測量的服務中斷上下文傳播。系統一定程度上正在裸跑。


2. eBPF 如何實現自動化測量

eBPF 通過從應用外部 —— 內核層面觀察應用來解決這個問題。

eBPF 能看到什麼

由於 eBPF 會鈎入內核函數和系統調用,可以觀察到:

|層|eBPF 看見|
|-|-|
|網絡|每一次 TCP 連接、HTTP 請求/響應、DNS 查詢|
|系統調用|文件 I/O,進程創建,內存分配|
|用户功能|函數通過 uprobe 進入/退出(如果有符號)|
|語言運行時|Go、Node.js、Python、Java 運行時內部結構|

這些如何成為 OpenTelemetry 數據

基於 eBPF 的自動化測量工作原理:

  1. 探針附加到已知入口點(HTTP 庫、gRPC 處理器、數據庫驅動程序)
  2. 從請求中提取上下文(從頭部提取追蹤 ID、請求元數據)
  3. 利用內核時間戳測量時序
  4. 關聯相關請求/響應對
  5. 導出為標準 OpenTelemetry Protocol(OTLP)數據

3. eBPF + OpenTelemetry 架構

典型生產配置如下:

組件

|組件| 職責|
|-|-|
|eBPF 代理|運行在每個節點上,連接 eBPF 程序,生成遙測數據|
|OTel 收集器|接收、處理 OTLP 數據,並導出到後端|
|後端|存儲和可視化追蹤/指標(OneUptime、Jaeger、Tempo)|

部署模式
模式 1:DaemonSet(Kubernetes)
# 運行在每個 node 上的 eBPF 代理
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ebpf-auto-instrumenter
spec:
  selector:
    matchLabels:
      app: ebpf-agent
  template:
    spec:
      hostPID: true      # eBPF 需要
      hostNetwork: true  # 網絡追蹤需要
      containers:
      - name: agent
        securityContext:
          privileged: true  # eBPF 需要
模式 2:Sidecar(每個 Pod 一個)
# eBPF 代理作為 sidecar (更為隔離,更多開銷)
spec:
  containers:
  - name: my-app
    image: my-app:latest
  - name: ebpf-sidecar
    image: ebpf-agent:latest
    securityContext:
      privileged: true
模式 3:獨立(非 Kubernetes)
# 直接在主機上運行
sudo ./beyla --config config.yaml

4. 工具比較:Odigos vs Beyla vs Pixie

下面比較幾種將 eBPF 與 OpenTelemetry 結合起來的工具。

Grafana Beyla

|特色|詳情|
|-|-|
|重點|HTTP/gRPC 自動監測|
|語言|Go, Python, Node.js, Java, Rust, .NET, Ruby|
|輸出|OTLP (追蹤 + 指標)|
|部署|獨立二進制或 Kubernetes|
|許可證|Apache 2.0|
|最佳實踐|簡單部署,Grafana 技術棧用户|

Odigos

|特色|詳情|
|-|-|
|重點|帶上下文傳播的全分佈式追蹤|
|語言|Go, Python, Node.js, Java, .NET|
|輸出|OTLP(追蹤)|
|部署|Kubernetes 原生(operator)|
|許可證|Apache 2.0|
|最佳實踐|Kubernetes 環境,分佈式追蹤|

Pixie

|特色|詳情|
|-|-|
|重點|全棧可觀測性,帶集羣內存儲|
|語言|Go, C/C++, Python, Node.js, Java, Rust|
|輸出|Pixie 格式(可導出為 OTel)|
|部署|僅限 Kubernetes|
|許可證|Apache 2.0|
|最佳實踐|調試、臨時查詢、全面可視化|

快速決策指南


5. 設置 Beyla(Grafana 的 eBPF 自動化測量)

Beyla 是入門基於 eBPF 的 OpenTelemetry 測量的最簡單方式。

前置條件
  • Linux 內核 5.8+(支持 BTF)
  • Root/privileged 訪問
  • 目標應用程序正在運行
安裝
# 下載最新版本
curl -LO https://github.com/grafana/beyla/releases/latest/download/beyla-linux-amd64.tar.gz
tar xzf beyla-linux-amd64.tar.gz
sudo mv beyla /usr/local/bin/
配置

創建 beyla-config.yaml

# beyla-config.yaml
open_port: 8080  # 測量進程監聽端口

# 或目標的可執行名稱
# executable_name: "my-service"

# 或進程 ID
# pid: 12345

# OTLP 導出配置
otel_traces_export:
  endpoint: http://localhost:4317  # OTel 收集器

otel_metrics_export:
  endpoint: http://localhost:4317
  
# 可選: 添加資源參數
attributes:
  kubernetes:
    enable: true  # 自動檢測 K8s 元數據
  
# 採樣 (可選)
traces:
  sampler:
    name: parentbased_traceidratio
    arg: "0.1"  # 10% 採樣
運行 Beyla
# 通過配置文件執行
sudo beyla --config beyla-config.yaml

# 或者通過環境變量
sudo BEYLA_OPEN_PORT=8080 \
     OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
     beyla
Kubernetes 部署
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: beyla
  namespace: observability
spec:
  selector:
    matchLabels:
      app: beyla
  template:
    metadata:
      labels:
        app: beyla
    spec:
      hostPID: true
      serviceAccountName: beyla
      containers:
      - name: beyla
        image: grafana/beyla:latest
        securityContext:
          privileged: true
          runAsUser: 0
        env:
        - name: BEYLA_OPEN_PORT
          value: "8080,3000,9090"  # 測量端口
        - name: OTEL_EXPORTER_OTLP_ENDPOINT
          value: "http://otel-collector.observability:4317"
        - name: BEYLA_KUBE_METADATA_ENABLE
          value: "true"
        volumeMounts:
        - name: sys-kernel
          mountPath: /sys/kernel
          readOnly: true
      volumes:
      - name: sys-kernel
        hostPath:
          path: /sys/kernel
Beyla 採樣數據

運行後,Beyla 會自動生成:

追蹤

  • HTTP 服務器 span(方法、路徑、狀態、時長)
  • HTTP 客户端 span(外出請求)
  • gRPC span(方法,狀態)
  • SQL 查詢 span(如果使用支持的驅動)

指標

  • http.server.request.duration(直方圖)
  • http.server.request.body.size
  • http.client.request.duration
  • rpc.server.duration
  • rpc.client.duration

6. 為 Kubernetes 設置 Odigos

Odigos 提供了更全面的分佈式追蹤,並實現了自動上下文傳播。

安裝
# 安裝 Odigos CLI
brew install odigos-io/homebrew-odigos-cli/odigos

# 或者直接下載
curl -LO https://github.com/odigos-io/odigos/releases/latest/download/odigos-cli-linux-amd64
chmod +x odigos-cli-linux-amd64
sudo mv odigos-cli-linux-amd64 /usr/local/bin/odigos
部署到 Kubernetes
# 在集羣裏安裝 Odigos
odigos install

# 創建:
# - odigos-system namespace
# - Odigos operator
# - Instrumentor DaemonSet
# - OTel Collector (可選)
配置目的地
# 添加可觀測性後端
odigos ui

# 或通過 CLI
odigos destination add oneuptime \
  --endpoint https://otlp.oneuptime.com \
  --api-key YOUR_API_KEY
測量命名空間
# 測量命名空間中的所有工作負載
odigos instrument namespace my-app-namespace

# 或指定工作負載
odigos instrument deployment my-service -n my-namespace
Odigos 運作方式

Odigos 比簡單的 eBPF 追蹤更智能:

  1. 語言檢測:自動檢測運行時(Go、Java、Python 等)
  2. 合適的測量方式:Go 使用 eBPF,Java/Python 注入代理
  3. 上下文傳播:確保跨越服務邊界追蹤上下文
  4. 無代碼更改:所有注入均發生在運行時


7. 自動獲取的內容

以下是基於 eBPF 工具能自動獲取或者不能獲取的內容:

自動獲取

|信號|詳情|
|-|-|
|HTTP 服務器請求|方法、路徑、狀態碼、時長、消息頭|
|HTTP 客户端請求|發送請求,含目的地和時間|
|gRPC 調用|方法、狀態、時長(包括服務器和客户端)|
|數據庫查詢|查詢文本、時長、數據庫類型(因工具而異)|
|DNS 查詢|域、查詢時間、結果|
|TCP 連接|源、目的、傳輸字節數|
|TLS 握手|證書信息,握手時間|

部分獲取(因工具/語言而異)

|信號|侷限性|
|-|-|
|消息隊列|Kafka/RabbitMQ 的支持各不相同,可能需要手動設置|
|自定義協議|需要特定工具的支持|
|內部函數調用|只有在符號信息可用的情況下|
|業務邏輯上下文|無法推斷用户 ID、訂單 ID 等信息|

無法獲取(需要手動測量)

|信號|為什麼|
|-|-|
|自定義 span 屬性|eBPF 不知道業務域|
|應用錯誤|異常詳情,stack trace(部分)|
|自定義指標|業務關鍵績效指標(KPI),轉化率|
|Baggage/Context|自定義傳播數據|


8. 將 eBPF 數據與手動測量進行關聯

最佳方法通常是混合式:基礎覆蓋用 eBPF,重要細節用手動測量。

策略:分層測量

示例:混合配置
// Go 服務 - eBPF 自動捕獲 HTTP 處理
// 為重要業務邏輯添加手動 span

func (s *OrderService) CreateOrder(ctx context.Context, req *OrderRequest) (*Order, error) {
    // eBPF已經獲取:HTTP POST /orders、計時、狀態

    // 業務邏輯細節的手動 span
    ctx, span := tracer.Start(ctx, "order.validate")
    err := s.validateOrder(ctx, req)
    span.End()
    if err != nil {
        // 手動:添加 eBPF 看不到的錯誤細節
        span.RecordError(err)
        span.SetStatus(codes.Error, "validation failed")
        return nil, err
    }
    
    // eBPF 自動捕獲數據庫調用
    // 手動:添加業務上下文
    ctx, span = tracer.Start(ctx, "order.save")
    span.SetAttributes(
        attribute.String("order.customer_id", req.CustomerID),
        attribute.Float64("order.total", req.Total),
        attribute.Int("order.items_count", len(req.Items)),
    )
    order, err := s.repo.Save(ctx, req)
    span.End()
    
    return order, err
}
確保相關性有效

為了讓 eBPF span 和手動 span 出現在同一條追蹤中:

  1. 相同的 Trace ID:eBPF 工具從輸入請求中提取 traceparent
  2. 上下文傳播:手動 span 必須使用相同的上下文
  3. 一致導出:eBPF 和手動測量都導出到同一個收集器
# OTel Collector 配置合併兩個源
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 1s
    
  # 添加一致的資源屬性
  resource:
    attributes:
      - key: deployment.environment
        value: production
        action: upsert

exporters:
  otlp:
    endpoint: https://oneuptime.com/otlp
    headers:
      x-oneuptime-token: ${ONEUPTIME_TOKEN}

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch, resource]
      exporters: [otlp]

9. 性能開銷

關鍵問題: 運行基於 eBPF 的自動化測量的成本是多少?

測量額外開銷

|工具|CPU 開銷|內存|時延影響|
|-|-|-|-|
|Beyla|1-3%|~50-100MB|< 1ms|
|Odigos|2-5%|~100-200MB|< 2ms|
|Pixie|2-5%|~500MB-1GB|< 1ms|

注意:實際開銷因工作負載、採樣率和追蹤端點數量而異。

增加額外開銷的因素

| 因素| 影響| 緩解措施|
|-|-|-|
| 高請求量|更多 eBPF 事件待處理| 增加採樣|
| 追蹤太多端點| 連接太多探針| 要有選擇性|
| 全載荷捕獲| 用於複製數據的內存/CPU|禁用或限制|
| 低採樣率| 更多數據需導出| 使用頭部採樣|

降低開銷
# Beyla 示例: 通過採樣降低開銷
traces:
  sampler:
    name: parentbased_traceidratio
    arg: "0.01"  # 1% 採樣

# 隔離高數據量、低價值的端點
routes:
  ignored:
    - /health
    - /ready
    - /metrics

10. 侷限性及何時使用手動測量

eBPF 自動測量功能強大,但並非魔法,需要知道取捨。

在以下情況下使用 eBPF 自動化測量

✅ 需要在多個服務中快速實現基線可觀測性

✅ 不能修改應用代碼(遺留版本,第三方代碼)

✅ 需要一致的 HTTP/gRPC/數據庫追蹤,而不是每個服務單獨設置

✅ 需要網絡層面的可視化(連接、DNS)

✅ 身處混合語言的 Kubernetes 環境中

需要使用手動測量

✅ 需要自定義業務屬性(用户 ID、訂單 ID、功能標誌)。

✅ 需要詳細的錯誤信息和 stack traces

✅ 需要自定義指標(業務關鍵績效指標、特定事件的計數器)

✅ 追蹤沒有 eBPF 支持的非 HTTP 協議

✅ 需要跨服務上下文的 baggage 傳播

✅ 要控制 span 名稱和結構

eBPF 自動化測量的侷限性

|限制|詳情|
|-|-|
|僅限 Linux|不支持沒有 Linux 內核的 Windows、macOS 或容器運行時|
|內核版本|需要 5.x 以上才能獲得最佳效果,部分功能需要 5.8 以上|
|特權訪問|必須提升權限運行(安全考慮)|
|符號可用性|剝離符號的 Go 二進制可執行文件會降低可見度|
|加密流量|TLS 檢查需要額外設置|
|應用上下文|無法從網絡數據推斷業務含義|


11. 最佳生產實踐

安全考量

運行 eBPF 代理需要提升權限。降低風險:

# Kubernetes: 嚴格使用 RBAC
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ebpf-agent-role
rules:
- apiGroups: [""]
  resources: ["pods", "nodes"]
  verbs: ["get", "list", "watch"]
# 避免授予不必要的權限
# 儘可能使用 seccomp 配置文件
securityContext:
  seccompProfile:
    type: RuntimeDefault
限制資源
containers:
- name: ebpf-agent
  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 512Mi
過濾與抽樣
# 不要追蹤每件事 —— 專注於重要的事情
routes:
  patterns:
    - /api/*        # Trace API calls
    - /graphql      # Trace GraphQL
  ignored:
    - /health       # Skip health checks
    - /metrics      # Skip metrics endpoint
    - /favicon.ico  # Skip static assets

# 通過採樣控制數據量
traces:
  sampler:
    name: parentbased_traceidratio
    arg: "0.1"  # 10% in production
逐步推廣
# 從非生產環境開始
odigos instrument namespace staging

# 驗證開銷和數據質量
# 然後擴展到生產環境
odigos instrument namespace production
監控
# 導出 eBPF 代理指標
prometheus:
  port: 9090
  path: /metrics

# 代理有問題時告警
# - 高 CPU 使用率
# - 事件丟失
# - 導出失敗

12. 結論

基於 eBPF 的自動化測量代表了可觀測性的範式轉變。通過將測量遷移到內核級,我們可以:

  • 消除測量負擔:不再按服務集成 SDK
  • 實現全覆蓋:觀察任何應用,任何語言
  • 減少盲點:發現那些被忽視的服務
  • 加快上線速度:新服務可立即被觀測到

但並不能完全取代傳統測量。最佳可觀測性策略結合了:

  1. eBPF 用於基線基礎設施層級可視化
  2. 針對特定框架上下文的自動化測量庫
  3. 為業務關鍵範圍和自定義屬性提供手動測量

像 Beyla 和 Odigo 這樣的工具讓入門變得前所未有的簡單。如果應用運行在 Kubernetes 和 Linux 上,只需要幾分鐘就可以實現整個分佈式追蹤技術棧。


要點

  1. eBPF 通過從內核觀測應用實現零代碼儀表化
  2. OpenTelemetry 兼容性意味着 eBPF 數據會流入現有可觀測棧
  3. 選擇合適的工具:Beyla 簡化應用,Odigos 支持 Kubernetes 分佈式追蹤,Pixie 負責調試
  4. 混合方法效果最佳:eBPF 用於覆蓋,手動測量用於業務環境
  5. 開銷低(1-5% CPU),但要監控並使用採樣
  6. 安全問題:eBPF 需要特權,授權範圍要適當
  7. 從小處開始:先從非生產環境開始,再擴展到生產環境

延伸閲讀

What is eBPF and How Does It Work? —— 深入探討 eBPF 基礎知識

Traces and Spans in OpenTelemetry —— 理解分佈式追蹤

What are Metrics in OpenTelemetry? —— 指標基礎

Logs, Metrics & Traces: The Three Pillars —— 完整的可觀察性概述

Basics of Profiling —— 需要更深入的性能洞察時


Hi,我是俞凡,一名兼具技術深度與管理視野的技術管理者。曾就職於 Motorola,現任職於 Mavenir,多年帶領技術團隊,聚焦後端架構與雲原生,持續關注 AI 等前沿方向,也關注人的成長,篤信持續學習的力量。在這裏,我會分享技術實踐與思考。歡迎關注公眾號「DeepNoMind」,星標不迷路。也歡迎訪問獨立站 www.DeepNoMind.com,一起交流成長。

本文由mdnice多平台發佈

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.