Linux

eBPF 全面介绍:从 Linux 内核机制到可观测性、网络、安全与 AIOps

·44 分钟阅读·17249 字

系统梳理 eBPF 的内核机制、程序加载、数据交换及云原生可观测性与安全应用

📋 目录

eBPF 全面介绍:从 Linux 内核机制到可观测性、网络、安全与 AIOps

从运维、SRE、Kubernetes 和 AIOps 的视角来看,eBPF 是非常值得深入学习的一项技术。它的重要性不只是“可以抓包”或者“可以监控系统调用”,而是因为它实际上给 Linux 内核提供了一种安全、动态、可编程的扩展机制:可以在不修改内核源码、不重新编译内核、通常也不需要编写传统内核模块的情况下,把自己的逻辑挂载到内核中的特定执行路径上。Linux 内核会在程序加载前使用 verifier 验证这些程序是否满足安全约束。(Linux Kernel 文档)

从运维、SRE 与云原生视角,可以概括为:

eBPF 的核心价值,是能够在“事件真正发生的地方”观察、统计甚至控制系统行为。

Prometheus 通常是在系统已经产生某个指标之后进行周期性采集,而 eBPF 可以进入系统调用、网络协议栈、调度器、文件系统、进程生命周期等内核路径,在事件发生时直接采集信息。正是这种能力,使 eBPF 成为现代 Linux 可观测性、云原生网络和运行时安全的重要底层技术。


1. 先理解传统 Linux 运维为什么需要 eBPF

假设线上出现一个问题:

某个 Kubernetes Pod API 延迟突然升高

通常会按照下面的路径排查:

Prometheus
   ↓
发现 API P99 延迟升高
   ↓
Grafana
   ↓
发现 CPU / IO / Network 指标异常
   ↓
kubectl logs
   ↓
应用日志
   ↓
strace / tcpdump / perf / ss / iostat
   ↓
逐步缩小问题

这些工具都很好,但它们存在一个共同问题:

不同工具只能看到系统中的某一层。

例如:

工具主要观察层
Prometheus指标
Grafana指标展示
logs应用事件
strace系统调用
tcpdump网络包
perfCPU / 性能事件
sssocket
iostat块设备
/proc内核统计

如果问题发生在这样的路径上:

Application
    ↓
glibc
    ↓
syscall
    ↓
Linux kernel
    ↓
TCP/IP
    ↓
NIC driver
    ↓
Network

传统监控工具往往只能看到:

CPU = 80%
IOPS = 30000
latency = 300ms

但真正需要判断的是:

哪个进程?
哪个 Pod?
调用了哪个 syscall?
访问了哪个文件?
连接了哪个 IP?
哪个 TCP connection?
在哪个内核函数耗时?
哪个磁盘请求慢?

eBPF 就是在解决这个问题。


2. eBPF 本质上是什么

eBPF 可以理解为 Linux 内核中的一个受限制的虚拟执行环境。

从架构角度看:

                   User Space
              ┌───────────────────┐
              │ eBPF Application  │
              │ Go / C / Rust ... │
              └─────────┬─────────┘
                        │
                        │ bpf() syscall / libbpf
                        ↓
┌──────────────────────────────────────────┐
│                Linux Kernel              │
│                                          │
│   ┌───────────────┐                      │
│   │ BPF Verifier  │                      │
│   └───────┬───────┘                      │
│           │                              │
│           ↓                              │
│   ┌───────────────┐                      │
│   │ eBPF Program  │                      │
│   └───────┬───────┘                      │
│           │                              │
│           ├── syscall                    │
│           ├── scheduler                  │
│           ├── TCP/IP                     │
│           ├── filesystem                 │
│           ├── cgroup                     │
│           ├── process                    │
│           └── device driver              │
│                                          │
│   ┌───────────────┐                      │
│   │   BPF Maps    │                      │
│   └───────┬───────┘                      │
└───────────┼──────────────────────────────┘
            │
            ↓
       User Space

整个工作过程大致为:

编写 eBPF 程序
      ↓
编译
      ↓
eBPF bytecode
      ↓
加载进 Linux kernel
      ↓
Verifier 验证
      ↓
JIT 编译成本机机器码
      ↓
Attach 到某个 Hook
      ↓
事件发生
      ↓
执行 eBPF 程序
      ↓
写入 BPF Map / Ring Buffer
      ↓
用户态程序读取
      ↓
日志 / Prometheus / Grafana / AI 分析

不同 eBPF program type 能做什么,取决于程序挂载的位置及对应内核接口;内核 verifier 会根据程序类型限制允许访问的数据和 helper。(eBPF 文档)


3. eBPF 最重要的概念:Hook

eBPF 不是一个长期运行的普通 Linux 进程。

它更接近:

WHEN something happens
    RUN this eBPF program

也就是:

事件
  ↓
Hook
  ↓
eBPF Program

例如:

进程执行
   ↓
execve syscall
   ↓
eBPF
   ↓
记录 PID / UID / command

或者:

TCP packet
   ↓
XDP
   ↓
eBPF
   ↓
DROP / PASS / REDIRECT

这也是理解 eBPF 最重要的一点:

eBPF 是事件驱动的内核程序。


4. eBPF 可以挂在哪里

这是整个 eBPF 技术体系最核心的部分。

4.1. Tracepoint

Linux 内核本身预先定义了很多 tracing point。

例如:

syscalls:sys_enter_openat
syscalls:sys_enter_execve
sched:sched_switch
sched:sched_process_exec
block:block_rq_issue
tcp:tcp_retransmit_skb

可以理解成 Linux 开发者预留的“观察接口”。

例如:

应用
 ↓
execve()
 ↓
Linux syscall
 ↓
tracepoint
 ↓
eBPF program

Tracepoint 的优点是接口相对稳定,因此非常适合作为生产环境 tracing 的入口。eBPF 有专门的 tracepoint program type 可以挂载到这些预定义内核 tracepoint。(eBPF 文档)


5. kprobe

如果内核没有提供需要的 tracepoint,就可以使用:

kprobe
kretprobe

它们可以挂载到 Linux kernel function。

例如:

tcp_v4_connect()

可以:

kprobe:tcp_v4_connect

这样每次内核调用:

tcp_v4_connect()

对应的 eBPF 程序都会执行。

比如:

process
    ↓
connect()
    ↓
tcp_v4_connect()
    ↓
kprobe
    ↓
eBPF

记录:

PID
process
src IP
dst IP
dst port
timestamp

因此就可以实现:

哪个进程
什么时候
连接了
哪个服务器
哪个端口

而不需要应用修改代码。Kprobe 本身不是 eBPF 特有功能,但 eBPF 可以通过相应 program type 与 kprobe 结合进行内核函数级 tracing。(eBPF 文档)


6. fentry / fexit

现代 eBPF tracing 越来越常使用:

fentry
fexit

它们可以理解成更现代的内核函数 tracing 方式。

例如:

tcp_v4_connect()

进入函数:

fentry

退出函数:

fexit

于是可以计算:

latency = exit_time - entry_time

例如:

start = now()

tcp_v4_connect()

end = now()

latency = end - start

这就是大量:

function latency tracing

工具的基本原理。

较新的 tracing program 可以利用 BPF trampoline,而不必完全依赖传统 kprobe 机制。(eBPF 文档)


7. uprobes:观察用户态程序

前面介绍的是:

kernel function

但如果想观察:

MySQL
Python
Redis
Nginx
JVM

就可以使用:

uprobe
uretprobe

例如:

mysqld

内部某个函数:

dispatch_command()

可以:

uprobe
    ↓
mysqld function

理论上就可以追踪:

MySQL 函数调用
latency
parameters
return value

同理:

Python interpreter
OpenSSL
glibc
Redis
Nginx

都可以进行用户态函数 tracing。


8. XDP:eBPF 最强大的网络能力之一

XDP 全称:

eXpress Data Path

普通 Linux 网络包路径大致为:

NIC
 ↓
Driver
 ↓
Linux network stack
 ↓
iptables
 ↓
TCP/IP
 ↓
socket
 ↓
Application

XDP 可以非常早地处理网络数据:

NIC
 ↓
Driver
 ↓
XDP eBPF
 ↓
Linux Network Stack

因此可以在一个网络包刚进入系统时决定:

PASS
DROP
REDIRECT
TX

例如:

Packet
   ↓
XDP
   ↓
if src_ip in blacklist:
       DROP
else:
       PASS

这就是为什么 eBPF 经常用于:

DDoS filtering
load balancing
packet filtering
network acceleration

XDP 还可以结合 devmap、cpumap 等 map 实现 packet redirect 等机制。Linux 官方文档明确将这些 map 与 XDP redirect 机制关联起来。(Linux Kernel 文档)


9. TC eBPF

除了 XDP,还有一个非常重要的网络位置:

Traffic Control

通常简称:

TC

例如:

NIC
 ↓
XDP
 ↓
Linux network stack
 ↓
TC ingress
 ↓
TCP/IP
 ↓
socket

或者出方向:

application
 ↓
socket
 ↓
TCP/IP
 ↓
TC egress
 ↓
NIC

TC 特别适合:

流量控制
网络策略
包修改
redirect
service routing

Cilium 等云原生网络系统大量利用类似的 Linux/eBPF datapath 能力。


10. cgroup eBPF

这对 Kubernetes 非常重要。

Linux container 的基础并不是所谓“容器内核”,而是:

namespace
+
cgroup
+
Linux kernel

因此 eBPF 可以挂载到 cgroup。

例如:

Pod
 ↓
container
 ↓
cgroup
 ↓
network connect
 ↓
eBPF

这时候就可以知道:

这个 connection 属于哪个 cgroup

进一步结合 Kubernetes metadata:

cgroup
 ↓
container ID
 ↓
Pod
 ↓
Namespace
 ↓
Deployment

于是:

10.42.2.8 → 10.42.3.9

这种传统网络信息,可以提升成:

namespace=order
pod=order-service-xxx

→

namespace=mysql
pod=mysql-primary

这就是 Kubernetes eBPF 网络可观测性的核心之一。


11. eBPF Program 到底长什么样

一个非常简化的 eBPF 程序可能类似:

SEC("tracepoint/syscalls/sys_enter_execve")
int trace_exec(struct trace_event_raw_sys_enter *ctx)
{
    u32 pid = bpf_get_current_pid_tgid() >> 32;

    bpf_printk("exec pid=%d\n", pid);

    return 0;
}

含义非常简单:

当 execve syscall 发生

↓

获取 PID

↓

输出信息

可以将其理解为:

@on_execve
def trace_exec(event):

    pid = get_pid()

    print(pid)

只不过 Python 这段代码运行在用户空间,而 eBPF 程序会经过 verifier,并最终运行在内核受控执行环境。


12. Verifier:为什么 eBPF 可以进入内核

这是 eBPF 最关键的设计。

如果普通程序随便在内核中执行:

pointer error
memory corruption
infinite loop
kernel panic

整个操作系统都可能崩溃。

因此 eBPF 程序加载的时候必须经过:

BPF Verifier

其核心目标是证明:

这个程序可以安全执行

Verifier 会做程序控制流和数据流分析,并检查指针、内存访问、程序路径及程序类型约束等安全规则。(eBPF 文档)

可以把传统 kernel module 和 eBPF 粗略理解成:

Kernel Module

Developer
   ↓
"相信代码"
   ↓
Kernel

而 eBPF 更像:

Developer
   ↓
eBPF bytecode
   ↓
Verifier
   ↓
安全?
 ↓   ↓
YES  NO
 ↓    ↓
Load Reject

这也是 eBPF 能够广泛用于动态观测和内核扩展的重要原因。


13. BPF Map:eBPF 最重要的数据结构

eBPF Program 本身适合处理事件,但通常还需要:

保存数据
统计数据
与用户空间通信

这就是:

BPF Map

例如:

key = PID
value = syscall_count

Map:

PID       syscall count

1001      10034
1002      3844
1003      89342

程序:

syscall
   ↓
eBPF
   ↓
map[pid]++

用户空间:

Prometheus exporter
       ↓
read BPF Map
       ↓
metrics

BPF map 本身位于内核空间,既可以被 eBPF 程序访问,也可以被用户态程序访问,因此它们实际上构成了 eBPF 内核程序与用户空间之间最重要的数据交换和持久化机制之一。(eBPF 文档)


14. 常见 BPF Map

最容易理解的是:

HASH
ARRAY
PERCPU_HASH
PERCPU_ARRAY
LRU_HASH

例如监控 TCP connection:

BPF_HASH

key:
    pid
    src_ip
    dst_ip
    dst_port

value:
    bytes
    packets
    latency

如果是高频事件,例如:

packet
syscall
scheduler

经常使用:

PERCPU_MAP

而不是所有 CPU 同时修改同一个 map。

原因是:

CPU0
CPU1
CPU2
CPU3

同时写一个 counter

会产生同步竞争。

Per-CPU map 变成:

CPU0 → counter0
CPU1 → counter1
CPU2 → counter2
CPU3 → counter3

最后用户空间:

sum(counter)

从而降低共享写竞争。Per-CPU map 是 Linux eBPF 中专门存在的一类 map。(eBPF 文档)


15. Ring Buffer:把事件送到用户空间

如果需要记录:

process exec

每次发生:

execve()

生成:

timestamp
pid
uid
command

就可以:

eBPF
 ↓
Ring Buffer
 ↓
User Space Program

例如:

15:31:01 pid=1032 bash
15:31:02 pid=1045 curl
15:31:03 pid=1056 python

因此可以把 eBPF 系统粗略理解成:

Hook
 ↓
BPF Program
 ↓
BPF Map / Ring Buffer
 ↓
User Space Agent
 ↓
Metrics / Logs / Events

16. Helper 与 kfunc

eBPF 不能像普通 C 程序一样随意调用 kernel function。

它主要通过内核提供的受控接口,例如 BPF helpers:

bpf_get_current_pid_tgid()
bpf_map_lookup_elem()
bpf_map_update_elem()

Linux 也逐渐提供:

BPF kfunc

即明确暴露给 BPF 程序使用的一部分内核函数。官方内核文档将 kfunc 描述为专门暴露给 BPF 程序使用的 kernel functions。(eBPF 文档)

所以:

eBPF
 ↓
Helper / kfunc
 ↓
Kernel capability

仍然处于明确限制中。


17. BTF 与 CO-RE

如果以后真正写 eBPF,这两个词一定会遇到:

BTF
CO-RE

BTF:

BPF Type Format

可以理解为:

Linux 内核数据结构的类型元信息。

例如内核有:

struct task_struct

不同内核版本:

5.15
6.1
6.6
...

结构字段和布局可能存在变化。

以前程序很容易产生:

kernel 5.x 可以运行
kernel 6.x 不能运行

现代 eBPF 采用:

CO-RE
Compile Once – Run Everywhere

结合 BTF,可以在不同内核版本中进行一定程度的结构适配。Linux 内核自己的 BPF Design Q&A 也明确建议使用 CO-RE,以降低不同 kernel version 内部数据结构变化造成的兼容问题。(Linux Kernel 文档)

这也是现在学习 eBPF 时应该优先理解的现代开发方式。


18. 为什么 Kubernetes 特别适合 eBPF

传统 Kubernetes 数据路径大致是:

Pod
 ↓
veth
 ↓
Linux network
 ↓
iptables / IPVS
 ↓
veth
 ↓
Pod

随着规模增大:

Service
NetworkPolicy
iptables rules

会变得越来越复杂。

而 eBPF 可以把部分逻辑直接程序化为:

packet
 ↓
eBPF
 ↓
Map lookup
 ↓
backend Pod

例如:

Service IP
10.96.0.10
      ↓
BPF map lookup
      ↓
10.42.1.3
10.42.2.7
10.42.4.12

这样网络数据面就变成了:

packet
 ↓
programmable datapath
 ↓
policy / load balancing / routing

而不是维护大量静态规则。


19. Cilium 就是非常典型的 eBPF 应用

Cilium 利用 eBPF 构建 Kubernetes networking/security datapath,而 Hubble 在其之上提供网络和安全可观测能力。官方文档将 Hubble 定义为构建在 Cilium/eBPF 之上的分布式 networking/security observability 平台。(Cilium 文档)

可以粗略理解为:

Kubernetes

   ↓

Cilium

   ↓

eBPF

   ↓

Linux Kernel

而:

Hubble

负责从这个 datapath 里把:

谁访问谁
请求是否被 drop
网络路径
L3/L4/L7 行为

表现出来。


20. eBPF 在运维与 SRE 中的应用

这里才是最值得关注的部分。

20.1. 系统调用监控

例如发现某个进程突然大量:

open()
read()
write()
connect()

可以统计:

Process        syscall       count

mysqld         read          920134
mysqld         write         321321
python         connect       843
nginx          accept        93434

这比:

CPU = 80%

深入得多。


21. 定位高 CPU

传统方法:

top

可能只能看到:

python  95%

eBPF profiling 可以继续分析:

Python
 ↓
function A
 ↓
function B
 ↓
function C

甚至结合 stack sampling 形成:

Flame Graph

于是问题从:

Python CPU 95%

变成:

80% CPU consumed by
function X
    ↓
JSON encode
    ↓
memory copy

这种能力对性能分析非常有价值。


22. 定位 IO 问题

例如:

MySQL replication lag

排查过程怀疑磁盘 I/O 存在异常。

Prometheus 只能看到:

disk latency
IOPS
util

eBPF 可以进一步 tracing:

process
 ↓
read/write syscall
 ↓
filesystem
 ↓
block layer
 ↓
device

于是可能得到:

mysqld pid=2341
write
size=128K
latency=120ms
device=nvme0n1

甚至进一步统计:

PID
container
IO size
IO latency
device
stack

此时定位问题的能力比只观察 iostat 高一个维度。


23. 定位 TCP 网络问题

例如:

API latency ↑

Prometheus:

HTTP P99 ↑

eBPF 可以继续追踪:

TCP connect latency
TCP retransmission
RTT
connection reset
packet drop

于是可以判断:

应用慢?

还是:

network RTT ↑

还是:

TCP retransmission ↑

还是:

packet drop ↑

这就是 eBPF 在网络 troubleshooting 中很重要的地方。


24. Kubernetes Pod 网络诊断

传统:

pod A
 ↓
service B

失败了。

此时可能需要:

kubectl exec
curl
nslookup
tcpdump
iptables
conntrack

如果采用 Cilium/Hubble 等 eBPF observability 能力,可以更直接地观察:

pod A
 ↓
TCP SYN
 ↓
NetworkPolicy
 ↓
DROP

甚至:

source:
namespace=order
pod=order-7832

destination:
namespace=payment
pod=payment-2341

port:
8080

verdict:
DROPPED

Hubble 的官方 CLI 文档就是围绕 inspecting network flows 设计的。(Cilium 文档)


25. 进程行为审计

例如,需要判断:

container

里面发生了什么。

可以监控:

exec
fork
open
connect
chmod
mount

例如:

Pod nginx

↓

/bin/bash

↓

curl 1.2.3.4

↓

chmod +x malware

这就是:

Runtime Security

领域。

Tetragon 就是典型案例,它利用 eBPF 进行 process execution、system call、network 和 file access 等安全观测,并支持 runtime enforcement。(GitHub)


26. 容器逃逸/异常行为检测

例如正常 nginx container 应该只是:

nginx

如果出现:

bash
curl
wget
nc
chmod
mount

eBPF 可以实时发现:

nginx
 ↓
execve("/bin/bash")
 ↓
eBPF event
 ↓
Security Agent
 ↓
Alert

再结合:

Pod
Namespace
Image
UID
Command

就可以形成:

Runtime security event

27. 数据库监控

在数据库资源池的运维场景中,eBPF 同样具有较高价值。

例如 MySQL:

mysqld

可以观察:

CPU
scheduler
disk IO
TCP
filesystem
syscall

因此可以做:

MySQL
    ↓
哪个实例?
    ↓
哪个 PID?
    ↓
IO latency?
    ↓
IO size?
    ↓
disk queue?

例如:

node
 ├ mysql instance A
 ├ mysql instance B
 └ mysql instance C

Prometheus:

disk util = 95%

只能说明磁盘忙。

eBPF 则可以继续回答:

instance A → 10%
instance B → 75%
instance C → 15%

这对于共享数据库节点非常有价值。


28. 可以把 eBPF 与 Prometheus 结合

架构可以设计成:

Linux kernel
     ↓
eBPF
     ↓
BPF maps
     ↓
Agent
     ↓
Prometheus metrics
     ↓
Prometheus
     ↓
Grafana

例如 eBPF 统计:

TCP retransmits
IO latency
syscall latency
packet drop

然后 exporter:

GET /metrics

输出:

ebpf_tcp_retransmits_total

ebpf_io_latency_seconds

ebpf_tcp_connect_latency_seconds

ebpf_syscall_duration_seconds

再由 Prometheus 采集。

这样就形成:

kernel
 ↓
eBPF
 ↓
metrics
 ↓
Prometheus
 ↓
Grafana

这是非常典型的 eBPF observability pipeline。


29. eBPF 与 AIOps 的关系其实非常密切

这一点值得特别关注。

AI 做异常检测或者根因分析,最大的问题之一通常不是:

模型不够强

而是:

数据不够丰富

传统监控:

CPU
memory
disk
network

只有几十、几百种 metrics。

eBPF 可以产生:

process
syscall
TCP
DNS
HTTP
file
IO
scheduler
container
stack

这种更加细粒度的数据。

于是:

eBPF
 ↓
Telemetry
 ↓
Metrics / Events / Traces
 ↓
Feature Engineering
 ↓
Anomaly Detection
 ↓
Root Cause Analysis

例如发生:

API latency ↑

AI 不只是看到:

CPU ↑

而可以看到:

API latency ↑
   ↓
TCP retransmission ↑
   ↓
node eth0 packet drop ↑
   ↓
NIC queue saturation

这样的因果链显然更容易构建 RCA。

所以从 AIOps 的角度,可以把 eBPF 看成:

Linux 内核级 telemetry 数据源。


30. eBPF 生态中应当知道哪些工具

学习 eBPF 时不要一开始就自己写 C。

先学会使用成熟工具。

一个比较合理的层次是:

Level 1
使用 eBPF 工具

Level 2
理解 Hook / Map / Program

Level 3
用 bpftrace 写 tracing

Level 4
使用 BCC

Level 5
libbpf + CO-RE

Level 6
开发自己的 agent

30.1. 第一类:bpftrace

非常适合运维。

例如:

bpftrace -e '
tracepoint:syscalls:sys_enter_execve
{
    printf("%d %s\n", pid, comm);
}'

可以将其理解为:

awk
+
DTrace
+
eBPF

非常适合:

临时故障排查
性能分析
事件追踪

31. BCC

BCC:

BPF Compiler Collection

提供大量现成工具。

例如常见思路包括:

exec tracing
TCP connection tracing
TCP retransmission tracing
block IO latency
filesystem latency
scheduler latency

学习阶段非常适合观察:

eBPF 到底能看到什么

而不需要立即解决 verifier、CO-RE、BTF 等开发问题。


32. libbpf

如果真正开发生产级 eBPF agent,目前比较重要的是:

libbpf
+
BTF
+
CO-RE

典型项目:

agent
 ├── xxx.bpf.c
 ├── xxx.h
 └── userspace loader

其中:

xxx.bpf.c

运行:

kernel space

用户态:

C / Go / Rust

负责:

load
attach
read events
export metrics

CO-RE 也是 Linux 官方 BPF 文档推荐用于提高跨内核适应性的机制。(Linux Kernel 文档)


33. Go + eBPF

如果需要开发:

AIOps Agent
Monitoring Agent
Network Agent
Security Agent

建议重点关注:

Go
+
eBPF

架构非常自然:

eBPF C program
        ↓
Kernel
        ↓
Ring Buffer
        ↓
Go Agent
        ↓
Prometheus
        ↓
Kafka
        ↓
AIOps

Go 负责:

Agent lifecycle
HTTP
Prometheus metrics
Kubernetes API
Kafka
configuration
event processing

eBPF 负责:

kernel telemetry

二者职责分离非常清楚。


34. 从整个系统架构看 eBPF

最终可以形成:

                Kubernetes

                    │
                    │ metadata
                    ↓

Linux Kernel → eBPF Agent
     │              │
     │              ├ process
     │              ├ syscall
     │              ├ network
     │              ├ IO
     │              └ scheduler
     │
     ↓
Ring Buffer / Maps
          │
          ↓
       Go Agent
          │
          ├────────→ Prometheus
          │
          ├────────→ Kafka
          │
          ├────────→ Loki
          │
          └────────→ OpenTelemetry
                         │
                         ↓
                       AIOps
                         │
                         ↓
               anomaly / RCA / alert

这实际上就是一个很有价值的 AIOps 数据采集 Agent 原型。


35. eBPF 入门项目设计

如果目标不只是学习语法,而是形成可落地的项目实践,则不建议从以下内容开始:

Hello eBPF

结束。

可以做一个:

35.1. Linux / Kubernetes eBPF Observability Agent

第一版只采集四类数据:

Process
Network
IO
System Call

例如:

Process

process_exec_total
process_exit_total

网络:

tcp_connect_total
tcp_retransmit_total
tcp_connect_latency

磁盘:

block_io_latency
block_io_size

系统调用:

syscall_count
syscall_latency

然后加入:

PID
process
container
Pod
namespace
node

metadata。

架构:

                 Linux Kernel

                     ↓

                    eBPF

          ┌──────────┼───────────┐
          ↓          ↓           ↓
       process     network       IO
          │          │           │
          └──────────┼───────────┘
                     ↓
                 Ring Buffer
                     ↓
                   Go Agent
                     ↓
               Prometheus
                     ↓
                  Grafana

第二阶段:

Kafka

第三阶段:

Python
↓
Pandas
↓
anomaly detection

第四阶段:

AI RCA Agent

最终:

eBPF
 ↓
Telemetry
 ↓
Prometheus / Kafka
 ↓
Feature engineering
 ↓
Anomaly Detection
 ↓
LLM RCA

这会把 Linux、Kubernetes、Go/Python、Prometheus、数据分析和 AIOps 串成一个完整工程。


36. 几个非常重要的误区

36.1. eBPF 不是 Prometheus 的替代品

更准确的关系是:

eBPF
=
data collection / kernel telemetry

Prometheus
=
time-series monitoring system

二者可以组合。


36.2. eBPF 也不是 tcpdump 的简单升级版

tcpdump 主要围绕:

packet

而 eBPF 能观察:

network
process
syscall
IO
scheduler
filesystem
security

范围远大于网络抓包。


36.3. eBPF 也不是传统 kernel module 的完全替代

eBPF 有严格的 verifier、program type、helper/kfunc、execution context 和内核能力限制。它的价值正来自这种受约束的可编程性,而不是“可以在内核里执行任意代码”。(eBPF 文档)


37. 真正理解 eBPF,可以记住这张图

                         EVENT
                           │
         ┌─────────────────┼─────────────────┐
         ↓                 ↓                 ↓
       syscall           network           scheduler
         │                 │                 │
         ↓                 ↓                 ↓
      Tracepoint           XDP              fentry
      kprobe               TC               tracepoint
      fentry              cgroup
         │                 │                 │
         └─────────────────┼─────────────────┘
                           ↓
                     eBPF Program
                           │
                  ┌────────┴────────┐
                  ↓                 ↓
               BPF Map         Ring Buffer
                  │                 │
                  └────────┬────────┘
                           ↓
                      User Space
                           ↓
                        Agent
                ┌──────────┼──────────┐
                ↓          ↓          ↓
            Prometheus    Logs      Kafka
                │                     │
                ↓                     ↓
             Grafana                  AI
                                      ↓
                                Anomaly / RCA

理解该图后,即可建立对 eBPF 整体体系的基本认知。


38. 建议的学习顺序

不要先钻 eBPF 指令集或者 verifier 源码。对运维/SRE/AIOps 路线,更合理的顺序是:

  1. **先学 bpftrace。**亲自追踪 execve、TCP connect、TCP retransmit、block IO latency,建立“Linux 事件 → Hook → eBPF”的直觉。
  2. **补 Linux 内核路径。**重点掌握 process/syscall、scheduler、VFS、block IO、socket、TCP/IP、cgroup 与 namespace。否则会写 eBPF,但不知道应该 attach 在哪里。
  3. **理解 eBPF 核心机制。**重点是 Program Type、Attach Point、Verifier、Helper、Map、Ring Buffer、BTF、CO-RE。
  4. **学习 BCC 和现成工具。**重点不是背命令,而是研究“一个 CPU/IO/network 问题如何通过 eBPF 定位”。
  5. **再进入 libbpf/CO-RE 开发。**自己写一个小型 eBPF observability agent。
  6. **最后进入 Kubernetes。**研究 Cilium、Hubble、Tetragon 的设计,可以发现以前 Kubernetes 网络、监控、安全很多彼此分散的知识开始连接起来。Cilium/Hubble 和 Tetragon 都是当前非常典型的 eBPF 云原生工程案例。(Cilium 文档)

38.1. 从相关技术方向来看,eBPF 最值得学习的不是“会写几个 BPF 程序”

真正有价值的是形成这样一套能力:

Linux 内核
      ↓
理解事件发生的位置
      ↓
选择正确 Hook
      ↓
eBPF 采集
      ↓
Go Agent
      ↓
Prometheus / Kafka
      ↓
数据处理
      ↓
异常检测
      ↓
RCA
      ↓
AIOps

这样 eBPF 就不再是一项孤立技术,而会把 Linux、Kubernetes、网络、性能分析、Prometheus、Go/Python 和 AIOps 串起来。

实践阶段可以从 execve 进程追踪器开始:先使用 bpftrace 观察完整的 用户命令 → syscall → tracepoint → eBPF → 用户态输出 执行链,再逐步改造成基于 Go、eBPF 与 Prometheus 的 Linux/Kubernetes Observability Agent。这一路线比直接学习大量 eBPF API 更容易形成系统认知。


关联文档

Yanche Blog

记录云原生、Linux、数据库等技术领域的学习心得,以及日常生活的思考与感悟。

© 2026 Yanche Blog. All rights reserved.

Powered by Astro