Linux eBPF技术

前言

对Linux操作系统的内核行为的观测和修改一般往往是基于Linux操作系统内置提供的命令和机制,例如使用iptables做流量控制或者从/proc目录获取一些可观测数据。这种传统方式主要的缺点是不灵活。而eBPF技术从近几年得到越来越大的重视,主要还是在于其提供了一种安全、灵活、高性能的方式使得我们可以更加高效地观测、改变内核行为,是一种未来的方向。

什么是eBPF以及为什么我们需要eBPF

eBPF全称是Extended Berkeley Packet Filter的缩写,最早来源于92年伯克利实验室的论文。不过其实现在的能力早就不仅仅与局限于网络保温过滤的功能了。本质是一个框架,允许用户在操作系统的内核中加载和运行自定义程序,可用于扩展甚至修改内核行为

为什么需要eBPF主要是过去对内核观测和修改存在如下限制:

  • 内核固化:内核代码首先不会让你随便修改,虽然有内核模块,但是编写完整的内核模块不是一件容易的事,同时问题的内核模块也会影响内核本身。
  • 不灵活:固化产生的另外个问题就是不灵活,如果需要一些自定义的内核修改、观测都比较困难。

eBPF框架机制提供如下优点可以解决以上问题:

  • 安全: eBPF框架本身提供了一个验证器(verifier)。验证器分析 eBPF 程序以确保无论任何输入,程序都将始终在有限指令数量内安全地终止。
  • 灵活:eBPF程序支持动态加载和卸载。

image.png

eBPF的前世今生

2014 年初,Alexei Starovoitov 实现了 eBPF(extended Berkeley Packet Filter)。经过重新设计,eBPF 演进为一个通用执行引擎,可基于此开发性能分析工具、软件定义网络等诸多场景。eBPF本身这种技术理念并不算新了,只不过现在随着Linux 4.9内核主干合并了eBPF主要功能,以及这个生态本身的繁荣使得其价值越来越大。eBPF本身属于动态追踪的技术领域,他的前辈还有Solaris OS的DTrace(21世纪初诞生)以及SystemTap。DTrace和内核关联紧密,但是D语言本身有些限制。SystemTap灵活性和易用性好一些,但是和内核关联不够紧密性能上相对差一些。综合来看eBPF现在更加代表未来一些。关于DTrace和SystemTap更多介绍可以看下动态追踪技术漫谈

动态追踪技术不需要应用配合,可以以极小的代价采集到一些关键运行时信息,这对在线诊断程序是非常有用的。如果对java比较熟悉的可能了解arthas,arthas相当于用于java的应用层的动态追踪工具。可以通过这种类比来快速立即动态追踪到底是什么玩意儿。

eBPF原理

eBPF程序本质是个虚拟机,可以执行eBPF字节码。可以将eBPF程序通过用户态映射到内核,挂载到不同的内核功能模块上:

  • 性能跟踪(kprobes/uprobes/tracepoints)
  • 网络(socket/xdp)
  • 容器(cgroup)
  • 安全(seccomp)

eBPF整体架构和工作流程如下:
image.png
用户空间程序与内核中的 BPF 字节码交互的流程主要如下:

  1. 使用 LLVM 或者 GCC 工具将编写的 BPF 代码程序编译成 BPF 字节码
  2. 使用加载程序 Loader 将字节码加载至内核。这里有很多工具链可以选择,bcc(支持python写)、libbpf(C写程序性能更好)等。
  3. 内核使用验证器(Verfier) 组件保证执行字节码的安全性,以避免对内核造成灾难,在确认字节码安全后将其加载对应的内核模块执行
  4. 内核中运行的 BPF 字节码程序可以使用两种方式将数据回传至用户空间
    • maps 方式可用于将内核中实现的统计摘要信息(比如测量延迟、堆栈信息)等回传至用户空间;
    • perf-event 用于将内核采集的事件实时发送至用户空间,用户空间程序实时读取分析;

如何发挥eBPF技术的价值

关注eBPF技术可能主要有以下两点价值:

参考资料