mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
3681 字
10 分钟
eBPF 零仪器化可观测性
2025-09-08

在前面的章节中,讨论的所有可观测性方案都需要某种形式的”仪器化”——无论是手动添加 OTel SDK 调用,还是注入 Java Agent。但对于那些你无法修改代码的遗留系统、第三方服务、或者内核态行为,这些方案都无能为力。

eBPF(Extended Berkeley Packet Filter)改变了这个局面。它允许你在不修改代码、不重启进程、不注入 Agent 的情况下,观测内核态和用户态的行为——这就是”零侵入可观测性”。

一、eBPF 基础#

1.1 什么是 eBPF?#

eBPF 是 Linux 内核的一个革命性特性——它允许你在内核态安全地运行沙箱化程序,而无需修改内核源码或加载内核模块。可以把 eBPF 理解为”内核的 JavaScript”——浏览器让你在网页中安全运行脚本,eBPF 让你在内核中安全运行观测程序。

eBPF 最初源于 BSD 包过滤器(BPF),用于网络数据包过滤(tcpdump 底层就是 BPF)。2014 年,Alexei Starovoitov 对 BPF 进行了大幅扩展,增加了映射表(Map)、辅助函数、JIT 编译等能力,这就是 eBPF。如今 eBPF 的应用早已超越网络领域,覆盖了可观测性、安全、网络、调度等多个方向。

graph TB subgraph 用户空间[" 用户空间"] APP["应用进程"] TOOL["eBPF 工具<br/>Beyla / bpftrace"] end subgraph 内核空间[" 内核空间"] VM["eBPF 虚拟机<br/>验证器 + JIT"] MAP["eBPF Maps<br/>数据共享"] HOOK["钩子点<br/>kprobes / uprobes / tracepoints"] end TOOL -->|"加载 BPF 程序"| VM VM -->|"挂载"| HOOK HOOK -->|"读取/写入"| MAP MAP -->|"用户态读取"| TOOL style 用户空间 fill:#e8eaf6,stroke:#283593 style 内核空间 fill:#e0f2f1,stroke:#00695c

1.2 eBPF 的工作原理#

eBPF 的工作流程可以概括为”编写 → 编译 → 加载 → 验证 → JIT → 挂载 → 执行”七个步骤:

  1. 编写:使用 C 或 BPF CO-RE(Compile Once – Run Everywhere)编写 eBPF 程序
  2. 编译:通过 LLVM/Clang 编译为 BPF 字节码
  3. 加载:用户态工具(如 libbpf)将字节码加载到内核
  4. 验证:内核验证器检查程序安全性(无无限循环、无越界访问、无未授权操作)
  5. JIT 编译:将字节码编译为本地机器码,获得接近原生的执行速度
  6. 挂载:将程序挂载到指定的钩子点(kprobe、tracepoint 等)
  7. 执行:钩子点触发时执行 eBPF 程序,通过 eBPF Maps 与用户态共享数据
cat > trace_open.c << 'EOF'
#include <uapi/linux/ptrace.h>
#include <linux/fs.h>
struct event {
u32 pid;
char comm[16];
char filename[256];
};
BPF_PERF_OUTPUT(events);
int trace_open(struct pt_regs *ctx, struct file *file) {
struct event e = {};
u32 pid = bpf_get_current_pid_tgid() >> 32;
e.pid = pid;
bpf_get_current_comm(&e.comm, sizeof(e.comm));
bpf_probe_read_kernel(&e.filename, sizeof(e.filename), file->f_path.dentry->d_name.name);
events.perf_submit(ctx, &e, sizeof(e));
return 0;
}
EOF
clang -O2 -target bpf -c trace_open.c -o trace_open.o
# python trace_open.py

1.3 eBPF 安全模型#

eBPF 的安全性由验证器保证,这是 eBPF 能在内核态安全运行的关键:

检查项说明
指令数限制程序不能超过 100 万条指令(防止无限循环)
内存访问只能访问明确允许的内存区域
函数调用只能调用白名单中的辅助函数
栈大小最多 512 字节栈空间
权限需要 CAP_BPF 或 root 权限加载
返回值必须确保所有执行路径都有返回值
Warning

eBPF 程序需要特权权限(CAP_BPF 或 root)才能加载。在生产环境中,应该严格控制 eBPF 程序的加载权限,避免安全风险。

二、eBPF 观测点#

2.1 内核态观测点#

观测点类型说明示例
kprobes动态内核函数入口/出口tcp_sendmsgext4_file_write
tracepoints静态内核预定义的追踪点sched:sched_switchnet:net_dev_xmit
kretprobes动态内核函数返回追踪函数返回值和耗时
perf_events性能硬件性能计数器CPU 周期、缓存未命中

2.2 kprobes 与 tracepoints 深入#

kprobes 和 tracepoints 是 eBPF 可观测性最核心的两个观测点类型,理解它们的区别是选择追踪策略的前提:

kprobes(内核探针) 是动态追踪机制,可以在任意内核函数的入口或返回点插入 eBPF 程序:

bpftrace -e '
kprobe:tcp_v4_connect {
printf("PID=%d COMM=%s: tcp_v4_connect called\n", pid, comm);
}
kretprobe:tcp_v4_connect {
printf("PID=%d COMM=%s: tcp_v4_connect returned %d\n", pid, comm, retval);
}
'

tracepoints(追踪点) 是内核开发者预定义的静态追踪点,比 kprobes 更稳定:

bpftrace -l 'tracepoint:*'
维度kprobestracepoints
稳定性低(内核函数可能变化)高(ABI 稳定)
覆盖范围任意内核函数仅预定义追踪点
性能开销略高略低
参数访问需要知道函数签名结构化参数,文档化
生产推荐谨慎使用优先使用

2.3 用户态观测点#

观测点类型说明示例
uprobes动态用户态函数入口SSL read/write、HTTP 解析
uretprobes动态用户态函数返回函数耗时
USDT静态用户态预定义的追踪点Python、Node.js 内置探针

uprobes 是 eBPF 实现零侵入 HTTP/gRPC 追踪的关键——它可以在不修改应用代码的情况下,拦截用户态函数调用:

bpftrace -e '
uprobe:/app/order-service:net/http.(*conn).serve {
printf("HTTP request started: PID=%d\n", pid);
}
uretprobe:/app/order-service:net/http.(*conn).serve {
printf("HTTP request completed: PID=%d\n", pid);
}
'

2.4 网络观测点#

graph LR subgraph 网络栈 NIC["网卡驱动<br/>XDP"] TC["TC 层<br/>ingress/egress"] SOCK["Socket 层<br/>cgroup/connect"] end NIC --> TC --> SOCK style NIC fill:#e3f2fd,stroke:#1565c0 style TC fill:#e8f5e9,stroke:#2e7d32 style SOCK fill:#fff3e0,stroke:#e65100

2.5 观测点选择决策#

不同观测场景需要选择不同的观测点。以下决策图帮助你快速选择:

graph TB Q1{"观测什么?"} -->|"内核函数"| Q2{"需要稳定性?"} Q2 -->|"是"| TP["tracepoints<br/>ABI 稳定"] Q2 -->|"否"| KP["kprobes<br/>任意内核函数"] Q1 -->|"用户函数"| UP["uprobes/uretprobes<br/>应用函数追踪"] Q1 -->|"网络数据"| Q3{"处理时机?"} Q3 -->|"最早"| XDP["XDP<br/>网卡驱动层"] Q3 -->|"稍晚"| TC_E["TC<br/>流量控制层"] Q3 -->|"应用层"| SOCK_E["Socket<br/>连接层"] Q1 -->|"性能计数"| PE["perf_events<br/>硬件计数器"] style Q1 fill:#e8eaf6,stroke:#283593 style TP fill:#c8e6c9,stroke:#2e7d32 style KP fill:#fff3e0,stroke:#e65100 style UP fill:#c8e6c9,stroke:#2e7d32 style XDP fill:#c8e6c9,stroke:#2e7d32 style TC_E fill:#c8e6c9,stroke:#2e7d32 style SOCK_E fill:#c8e6c9,stroke:#2e7d32 style PE fill:#c8e6c9,stroke:#2e7d32
网络观测点挂载位置用途
XDP网卡驱动层最早的数据包处理点,适合 DDoS 防护、负载均衡
TC流量控制层ingress/egress 数据包过滤和追踪
cgroup/connectSocket 连接层追踪 TCP/UDP 连接建立
sockopsSocket 操作层追踪 Socket 读写事件

三、Beyla:eBPF 自动仪器化#

3.1 Beyla 架构深入#

Beyla 是 Grafana 生态的 eBPF 自动仪器化工具,无需修改代码即可产生 OpenTelemetry 追踪和指标。它的核心设计理念是”零配置、零代码、零侵入”:

graph TB subgraph 应用[" 应用进程"] APP1["Go 服务"] APP2["Java 服务"] APP3["Node.js 服务"] APP4["Rust 服务"] end subgraph Beyla[" Beyla (eBPF)"] DISC["服务发现<br/>K8s / Docker / Process"] INST["eBPF 仪器化<br/>HTTP/gRPC 拦截"] TRANS["OTLP 转换<br/>Span/Metric 生成"] PIPE["管道管理<br/>协议识别 + 路由"] end subgraph 后端[" 后端"] OTEL["OTel Collector"] TEMPO["Tempo"] PROM["Prometheus"] end APP1 -.->|"零侵入观测"| INST APP2 -.->|"零侵入观测"| INST APP3 -.->|"零侵入观测"| INST APP4 -.->|"零侵入观测"| INST DISC --> INST --> PIPE --> TRANS --> OTEL OTEL --> TEMPO OTEL --> PROM style 应用 fill:#e8eaf6,stroke:#283593 style Beyla fill:#e0f2f1,stroke:#00695c style 后端 fill:#fff3e0,stroke:#e65100

3.2 零仪器化原理#

Beyla 实现零仪器化的核心原理是:通过 eBPF 拦截应用进程的系统调用和函数调用,自动提取 HTTP/gRPC 请求信息,然后将其转换为 OpenTelemetry 信号。

整个流程分为五个阶段:

  1. 服务发现:自动发现 Kubernetes Pod 或 Docker 容器中的应用进程,识别进程的元数据(服务名、命名空间、Pod 名)
  2. eBPF 注入:在应用进程的 read/write 系统调用上挂载 eBPF 程序,拦截进出应用的网络数据
  3. 协议解析:从系统调用的数据中解析 HTTP/gRPC 协议头,提取请求方法、路径、状态码、耗时等信息
  4. Span 生成:根据解析结果生成 OpenTelemetry Span,自动填充服务名、操作名、状态码等属性
  5. OTLP 导出:通过 OTLP 协议导出到 OTel Collector 或直接导出到 Tempo/Prometheus

3.3 Beyla 配置#

routes:
patterns:
- name: "HTTP"
match:
kind: "HTTP"
operations: ["GET", "POST", "PUT", "DELETE"]
- name: "gRPC"
match:
kind: "gRPC"
export:
otel:
endpoint: "otel-collector:4317"
protocol: "grpc"
traces:
enabled: true
metrics:
enabled: true
discovery:
services:
- name: "order-service"
namespace: "production"
pod_labels:
app: "order-service"

3.4 Kubernetes 部署#

# Beyla DaemonSet
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: beyla
spec:
selector:
matchLabels:
app: beyla
template:
spec:
serviceAccountName: beyla
containers:
- name: beyla
image: grafana/beyla:latest
securityContext:
capabilities:
add: ["CAP_BPF", "CAP_SYS_PTRACE"]
env:
- name: BEYLA_OTEL_ENDPOINT
value: "otel-collector:4317"
- name: BEYLA_DISCOVERY
value: "auto"

四、eBPF 实现 HTTP 请求追踪#

4.1 HTTP 请求追踪原理#

Beyla 通过 eBPF 追踪 HTTP 请求的核心思路是:拦截应用进程的 read/write 系统调用,从数据缓冲区中解析 HTTP 协议头部:

sequenceDiagram participant Client participant App as 应用进程 participant eBPF as eBPF 程序 participant Map as eBPF Map participant User as Beyla 用户态 Client->>App: HTTP GET /api/orders App->>eBPF: read() 系统调用触发 eBPF->>eBPF: 解析 HTTP 请求行<br/>GET /api/orders eBPF->>Map: 记录请求开始时间<br/>存储 conn_id → (method, path, start_time) App->>App: 处理请求... App->>eBPF: write() 系统调用触发 eBPF->>eBPF: 解析 HTTP 响应状态码<br/>200 OK eBPF->>Map: 更新 conn_id → (method, path, start_time, status_code) User->>Map: 定期读取 Map User->>User: 生成 OTel Span<br/>name=GET /api/orders<br/>status=200<br/>duration=45ms User->>User: 通过 OTLP 导出

4.2 HTTP/1.1 解析#

on_sys_enter_read(ctx) {
buf = read_buffer(ctx);
method = parse_http_method(buf); # "GET"
path = parse_http_path(buf); # "/api/orders"
request_map[conn_id] = {
method: method,
path: path,
start_time: bpf_ktime_get_ns()
};
}
on_sys_enter_write(ctx) {
buf = read_buffer(ctx);
status = parse_http_status(buf); # 200
req = request_map[conn_id];
duration = bpf_ktime_get_ns() - req.start_time;
event_output({
method: req.method,
path: req.path,
status: status,
duration_ns: duration
});
}

4.3 HTTP/2 与 gRPC 解析#

HTTP/2 的解析比 HTTP/1.1 复杂得多——它使用二进制帧格式,头部经过 HPACK 压缩,需要维护压缩上下文:

维度HTTP/1.1HTTP/2
格式文本协议二进制帧
头部编码纯文本HPACK 压缩
多路复用无(每个连接一个请求)有(流 ID 区分请求)
解析复杂度高(需维护 HPACK 上下文)
eBPF 解析直接解析需要跟踪流状态

五、eBPF 实现 TCP 连接追踪#

5.1 TCP 连接追踪#

除了 HTTP 级别的追踪,eBPF 还可以在 TCP 层面追踪连接建立、数据传输和连接关闭:

bpftrace -e '
kprobe:tcp_v4_connect {
printf("PID=%d COMM=%s: tcp_v4_connect called\n", pid, comm);
}
kprobe:tcp_v4_connect {
printf("PID=%d COMM=%s: tcp_v4_connect called\n", pid, comm);
}
'
# - tcp_connection_opened_total
# - tcp_connection_closed_total
# - tcp_connection_duration_seconds
# - tcp_retransmissions_total

5.2 TCP 连接生命周期追踪#

sequenceDiagram participant Client participant Server participant eBPF Note over eBPF: kprobe:tcp_v4_connect Client->>Server: SYN Note over eBPF: 记录连接开始<br/>src_ip, dst_ip, src_port, dst_port Server->>Client: SYN+ACK Client->>Server: ACK Note over eBPF: tracepoint:sock:inet_sock_set_state<br/>状态: SYN_SENT → ESTABLISHED Client->>Server: 数据传输 Note over eBPF: tracepoint:net:net_dev_xmit<br/>记录字节数 Server->>Client: 数据传输 Client->>Server: FIN Server->>Client: FIN+ACK Note over eBPF: tracepoint:sock:inet_sock_set_state<br/>状态: ESTABLISHED → CLOSED<br/>计算连接持续时间

六、无代码变更的延迟测量#

6.1 延迟测量原理#

eBPF 可以在不修改应用代码的情况下测量请求延迟,其原理是在请求的入口和出口分别记录时间戳:

6.2 延迟测量精度#

测量方式精度开销适用场景
系统调用时间差毫秒级通用 HTTP/gRPC 延迟
uprobe 函数追踪微秒级精确函数耗时
TCP 连接时间毫秒级网络层延迟
tracepoint 调度微秒级内核调度延迟

6.3 延迟分布直方图#

eBPF 可以在内核态直接计算延迟分布直方图,避免将每个请求的延迟数据传输到用户态:

bpftrace -e '
uprobe:/app/order-service:net/http.(*conn).serve {
@start[tid] = nsecs;
}
uretprobe:/app/order-service:net/http.(*conn).serve /@start[tid]/ {
@latency = hist((nsecs - @start[tid]) / 1000000);
delete(@start[tid]);
}
'
# @latency:
# [1, 2) 1234 |@@@@@@@@@@ |
# [2, 4) 567 |@@@@ |
# [4, 8) 234 |@@ |
# [8, 16) 89 | |
# [16, 32) 45 | |
# [32, 64) 12 | |

七、eBPF 可观测性 vs SDK 可观测性#

7.1 对比#

维度eBPF 可观测性SDK 可观测性
侵入性零侵入需要修改代码或注入 Agent
覆盖范围内核态 + 用户态仅用户态
精确度中(基于系统调用推断)高(基于应用逻辑)
自定义属性有限(无法获取应用内部状态)丰富(可以添加任意属性)
语言支持所有语言需要各语言 SDK
遗留系统支持需要改造
内核行为可观测不可观测
性能开销低(~1-3%)中(~5-15%)
部署复杂度中(需要特权)低(SDK 集成)
业务语义弱(仅协议层信息)强(任意自定义属性)

7.2 适用场景#

场景推荐方案原因
新服务开发SDK 可观测性精确度高、自定义属性丰富
遗留系统改造eBPF 可观测性零侵入、无需修改代码
内核行为观测eBPF 可观测性SDK 无法观测内核
第三方服务eBPF 可观测性无法修改第三方代码
网络层观测eBPF 可观测性XDP/TC 层只有 eBPF 能触达
业务指标采集SDK 可观测性eBPF 无法获取业务语义

7.3 混合策略#

Note

eBPF 和 SDK 不是互斥的,而是互补的。最佳实践是:SDK 负责业务语义的信号(自定义属性、业务指标),eBPF 负责基础设施层的信号(网络、内核、零侵入追踪)

graph TB subgraph 应用层[" 应用层"] SDK["OTel SDK<br/>业务 Span + 指标<br/>自定义属性"] EBPF["Beyla (eBPF)<br/>基础设施 Span<br/>网络/内核指标"] end subgraph 管道层[" OTel Collector"] MERGE["信号合并<br/>SDK Span + eBPF Span<br/>关联 TraceID"] end subgraph 存储层[" 存储"] TEMPO["Tempo<br/>统一追踪"] PROM["Prometheus<br/>统一指标"] end SDK --> MERGE EBPF --> MERGE MERGE --> TEMPO MERGE --> PROM style 应用层 fill:#e8eaf6,stroke:#283593 style 管道层 fill:#e0f2f1,stroke:#00695c style 存储层 fill:#fff3e0,stroke:#e65100
信号类型SDK 负责eBPF 负责
追踪业务逻辑 Span(含自定义属性)基础设施 Span(网络/内核)
指标业务指标(订单量、转化率)基础设施指标(TCP 重传、调度延迟)
日志结构化日志(含 TraceID)内核日志(dmesg、审计日志)
性能分析应用级 Profile(pprof)内核级 Profile(perf_event)

八、eBPF 可观测性工具生态#

8.1 工具矩阵#

工具类型功能语言支持
Beyla自动仪器化HTTP/gRPC 追踪 + 指标所有语言
Pixie可观测性平台全栈可观测性所有语言
bpftrace动态追踪自定义追踪脚本所有语言
BCC工具集预定义追踪工具所有语言
Cilium网络可观测性网络策略 + 追踪所有语言
Parca Agent持续性能分析eBPF CPU/内存分析所有语言

8.2 bpftrace 实战#

# 追踪 TCP 连接建立
bpftrace -e '
kprobe:tcp_v4_connect {
printf("PID: %d, %s -> ", pid, comm);
printf("%s\n", ntop(arg2));
}
'
# 追踪 HTTP 请求延迟(uprobe)
bpftrace -e '
uprobe:/app/order-service:net/http.(*conn).serve {
@start[tid] = nsecs;
}
uretprobe:/app/order-service:net/http.(*conn).serve /@start[tid]/ {
@latency = hist((nsecs - @start[tid]) / 1000000);
delete(@start[tid]);
}
'
# 追踪文件 I/O 延迟
bpftrace -e '
kprobe:vfs_read {
@start[tid] = nsecs;
}
kretprobe:vfs_read /@start[tid]/ {
@read_ns = hist(nsecs - @start[tid]);
delete(@start[tid]);
}
'

8.3 BCC 工具集#

BCC(BPF Compiler Collection)提供了一组预定义的可观测性工具:

# CPU 分析
execsnoop # 追踪新进程创建
opensnoop # 追踪文件打开
profile # CPU 性能分析(类似 perf)
# 内存分析
memleak # 检测内存泄漏
slabratetop # 内核 SLAB 分配速率
# 网络
tcpconnect # 追踪 TCP 活跃连接
tcpaccept # 追踪 TCP 被动连接
tcpretrans # 追踪 TCP 重传
tcplife # 追踪 TCP 连接生命周期
# I/O
biolatency # 块设备 I/O 延迟直方图
biosnoop # 块设备 I/O 追踪
filelife # 文件生命周期追踪

九、eBPF 可观测性的局限性#

9.1 当前局限#

局限说明缓解方案
权限要求需要 CAP_BPF 或 root使用 DaemonSet 部署,限制权限
内核版本部分功能需要 5.x+ 内核使用 CO-RE 提高兼容性
协议解析仅支持 HTTP/gRPC/Redis 等持续扩展协议支持
自定义属性无法获取应用内部状态结合 SDK 补充业务属性
调试困难eBPF 程序调试工具有限使用 bpftool 和 bpf_trace_printk
性能开销高频事件可能产生显著开销使用采样和过滤
HTTPS 解析需要挂载 SSL 函数uprobe 挂载 OpenSSL/BoringSSL

9.2 未来展望#

  • WASM eBPF:用 WebAssembly 编写 eBPF 程序,提高可移植性
  • eBPF CO-RE:一次编译,到处运行,无需为目标内核单独编译
  • 更多协议支持:MySQL、PostgreSQL、Kafka 等数据库和消息协议
  • 与 OTel 深度集成:eBPF 产生的信号自动关联 SDK 产生的信号

十、生产部署#

10.1 部署架构#

graph TB subgraph K8s集群[" Kubernetes 集群"] subgraph Node1["Node 1"] POD1["应用 Pod 1"] BEYLA1["Beyla DaemonSet"] end subgraph Node2["Node 2"] POD2["应用 Pod 2"] BEYLA2["Beyla DaemonSet"] end end subgraph 监控栈[" 监控栈"] OTEL["OTel Collector"] TEMPO["Tempo"] PROM["Prometheus"] GRAFANA["Grafana"] end BEYLA1 -->|"OTLP"| OTEL BEYLA2 -->|"OTLP"| OTEL OTEL --> TEMPO OTEL --> PROM GRAFANA --> TEMPO GRAFANA --> PROM style K8s集群 fill:#e8eaf6,stroke:#283593 style 监控栈 fill:#e0f2f1,stroke:#00695c

10.2 资源规划#

# Beyla DaemonSet 资源配置
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
规模节点数Beyla 总 CPUBeyla 总内存OTel Collector
小型(< 20 节点)202 核2.5 GiB1 实例,2 核
中型(20-100 节点)10010 核12.5 GiB3 实例,4 核
大型(> 100 节点)50050 核62.5 GiB10 实例,8 核

10.3 安全考量#

# Beyla 最小权限配置
securityContext:
capabilities:
add: ["CAP_BPF", "CAP_SYS_PTRACE"]
readOnlyRootFilesystem: true
# 注意: eBPF 需要 root 权限
runAsNonRoot: false
# RBAC 权限
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list", "watch"]
Warning

eBPF 程序需要特权权限才能加载。在多租户环境中,务必将 Beyla 部署在独立的命名空间,并限制其 RBAC 权限。不要让普通用户有权加载 eBPF 程序或查看其他租户的追踪数据。

10.4 生产部署检查清单#

检查项验证方式预期结果
内核版本uname -r≥ 5.4(推荐 5.10+)
eBPF 权限bpftool feature probe支持所需特性
Beyla 运行kubectl logs无错误日志
服务发现Beyla 日志发现应用进程
追踪导出Tempo 查询能看到自动产生的 Span
指标导出Prometheus 查询能看到请求速率/延迟指标
性能开销应用 P99 延迟对比开销 < 3%

十一、动手实践:搭建 eBPF 可观测性#

11.1 部署 Beyla#

# Kubernetes 部署
kubectl apply -f beyla-daemonset.yaml
# 验证 Beyla 运行
kubectl logs -n monitoring daemonset/beyla

11.2 验证零侵入追踪#

# 发送 HTTP 请求到应用
curl http://localhost:8080/api/v1/orders
# 在 Grafana 中查看自动产生的追踪
# 1. 打开 Grafana Explore
# 2. 选择 Tempo 数据源
# 3. 搜索 service.name = "order-service"
# 4. 确认能看到 Beyla 自动产生的追踪

11.3 验证清单#

检查项验证方式预期结果
Beyla 运行kubectl logs无错误日志
自动发现服务Beyla 日志发现应用进程
HTTP 追踪Grafana 查询能看到自动产生的 Span
gRPC 追踪Grafana 查询能看到 gRPC Span
指标导出Prometheus 查询能看到请求速率/延迟指标

十二、本章小结#

上一章了解了持续性能分析与火焰图。 本章探索了 eBPF 零侵入可观测性:

主题核心要点关键词
eBPF 原理在内核态安全运行沙箱化程序,无需修改代码或重启进程。验证器保证安全性,JIT 编译保证性能。eBPF 原理
观测点kprobes/tracepoints(内核态)、uprobes/USDT(用户态)、XDP/TC(网络)。生产环境优先使用 tracepoints。观测点
BeylaeBPF 自动仪器化工具,零侵入产生 OTel 追踪和指标。通过拦截系统调用解析 HTTP/gRPC 协议。Beyla
HTTP 追踪拦截 read/write 系统调用,解析 HTTP 协议头部,自动生成 Span。HTTP 追踪
TCP 追踪通过 kprobes 和 tracepoints 追踪 TCP 连接生命周期。TCP 追踪
延迟测量在内核态直接计算延迟直方图,避免大量数据传输。延迟测量
eBPF vs SDK互补而非互斥——SDK 负责业务语义,eBPF 负责基础设施层。eBPF vs SDK
局限性权限要求、协议解析有限、无法获取应用内部状态、HTTPS 解析需要额外处理。局限性
生产部署DaemonSet 部署、最小权限、资源规划、内核版本检查。生产部署

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

eBPF 零仪器化可观测性
https://blog.souloss.com/posts/observability/observability-ebpf-observability/
作者
Souloss
发布于
2025-09-08
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时