eBPF 是一种可以在特权上下文(例如操作系统内核)中运行程序的技术。它是 Linux 中 Berkeley Packet Filter(BPF,其中“e”最初表示“扩展”)过滤机制的后继者,也用于 Linux 内核的非网络部分。
它用于在运行时安全高效地扩展内核的功能,而无需更改内核源代码或加载内核模块。安全性通过内核验证程序提供,该验证程序执行静态代码分析并拒绝崩溃、挂起或以其他方式对内核造成负面影响的程序。
字节跳动求助于 eBPF 来解决这些挑战。eBPF 是一种强大的技术,可以动态安全地重新编程 Linux 内核,帮助该公司重新设计其容器网络堆栈。实施过程中的关键步骤包括:
- 字节跳动采用了netkit,这是 Linux 内核 6.8 版中引入的由 eBPF 驱动的网络设备,在容器网络中比传统虚拟以太网提供了更优越的性能。
- 为了适应现有的限制和遗留部署,netkit 被反向移植到内核版本 5.15,以确保与字节跳动基础设施的兼容性。
精心策划的升级过程确保了最小的中断。容器网络接口和内核升级都是独立管理的,允许逐步过渡到 netkit。
人们担心混合部署可能存在问题,因此在整个过渡过程中确保了 netkit 和虚拟以太网之间的兼容性。
实施了回退机制来处理 netkit 或其相关的 eBPF 程序失败的情况,以确保服务不中断。
Netkit
Netkit 是一个基于 eBPF 技术的网络工具,它的核心思想是让数据包在容器或虚拟机之间传输时更加高效和简单。
传统方式的问题
在传统的网络方案中,为了让容器或虚拟机之间通信,通常会给每个容器或虚拟机分配一个虚拟网络设备(veth)。这些设备虽然看起来像真实的以太网设备,但实际上并不是。内核网络堆栈在处理这些设备时,会像处理真实以太网设备一样走完整的网络协议栈,这会导致一些不必要的开销。
Netkit 用 eBPF 技术简化了这个过程。它不再依赖复杂的虚拟网络设备,而是直接用 eBPF 程序来处理数据包的发送和接收。具体来说:
- 发送:当一个容器或虚拟机要发送数据包时,eBPF 程序会直接把它传递给目标容器或虚拟机。
- 接收:目标容器或虚拟机的 eBPF 程序会直接接收这个数据包。
这种方式绕过了传统网络协议栈的复杂逻辑,直接在共享的内核中完成数据包的传输,因此速度更快,逻辑也更简单。
为什么 Netkit 更好?
- 更快:因为跳过了很多不必要的网络协议栈处理,数据包传输速度更快。
- 更简单:Netkit 的代码(比如 netkit.c)非常简洁易懂,容易理解和维护。
- 更高效:eBPF 程序直接在内核中运行,减少了用户态和内核态之间的切换开销。
结果
eBPF 和 netkit 的部署为字节跳动的数据中心带来了显著的改进:
- 性能提升:
- 消除了网络堆栈中的最后一个软中断,从而使吞吐量提高了 10%。
- 解决了虚拟以太网导致的 CPU 负载过高和数据包重新排序的问题,提高了整体效率。
- 可扩展性和稳定性:
- 成功在数十个集群中部署了 netkit,证明了其可靠性和更广泛采用的准备程度。
- 运营效益:
- 简化网络堆栈,减少维护开销并提高系统可观察性。
字节跳动 TikTok 基础设施的更完整图景
他们发布了“KubeAdmiral”:https ://github.com/kubewharf/kubeadmiral
估计他们通过 Kubernetes CNI 使用 eBPF,而且看到字节跳动在 Cilium 的 github 上有列出:https://github.com/cilium/cilium/blob/main/USERS.md
他们还在使用 KubeRay来协调庞大的推理任务:https://www.anyscale.com/blog/how-bytedance-scales-offline-i...
他们还制作了 monoio,一个基于 io-uring 的 Rust 异步运行时:https ://github.com/bytedance/monoio