本文地址:https://www.ebpf.top/post/cloudflare-replatforming-5/

原文地址:Cloudflare’s eBPF Replatforming Part 5: Tips for Operating eBPF at Scale

原作者:Cloudflare Engineering
发布时间:2026 年 10 月 29 日
译者:狄卫华
许可:原文采用 CC BY 4.0 许可,本文为其中文翻译,并进行了必要的语言与格式适配。

本系列记录了 Cloudflare 使用 eBPF 的八年历程:它从一项专门用于抵御分布式拒绝服务攻击(DDoS)的工具,发展为其全球网络的可编程骨干。内容涵盖向 Linux 内核贡献代码、应对技术挑战、业务投资回报(ROI),以及为其他采用 eBPF 的公司提供的建议与运维策略。

在前几篇文章中,我们介绍了 Cloudflare 如何利用 eBPF,从绕过传统套接字(socket)API 的限制,到实现分布式 XDP 攻击缓解流水线,以及 BPF Linux 安全模块(LSM)安全策略。不过,在本地测试机上管理 BPF 对象,与在遍布全球、覆盖超过 330 个站点的服务器集群中将其投入运行,是截然不同的事情。

本文将重点转向在生产环境中安全运行 eBPF 所需的部署机制与运维保障。在这一全球服务器集群中安全部署 eBPF 程序,需要多个相互配合的层次:以内核 eBPF 验证器(verifier)作为第一道关卡,进行全面的生产前测试,历时多天、逐步覆盖更大流量范围的分阶段发布,用功能开关(feature flag)将功能启用与二进制部署解耦,通过 bpf_link 原子替换程序,利用平滑重载(graceful reload)机制在升级期间维持数据平面(data plane)运行,借助固定的 BPF map(pinned BPF maps)在守护进程崩溃后保留状态,以及通过配置管理处理站点特有的逻辑。

1. BPF 验证器:第一道安全关卡

每个加载的 eBPF 程序都必须先通过内核的 BPF 验证器,才能执行。验证器提供了传统部署流程无法提供的硬性保证:

  • 禁止非法内存访问:验证器对每条代码路径进行静态分析,拒绝可能解引用空指针(NULL)或越界访问内存的程序。
  • 禁止无限循环:验证器会检测并拒绝包含无法终止的循环的程序。
  • 强制限制栈大小:BPF 程序的栈大小上限为 512 字节;使用 BPF_MAP_TYPE_PROG_ARRAY 进行尾调用(tail call)的程序,上限还会更低。超过上限的程序会在加载时被拒绝。

【译者注:这里保留原文对 512 字节栈限制的概括。具体上限取决于内核版本、架构及调用方式等条件;当前内核设计问答已说明,支持较大栈的部分 JIT 架构可使用至多 2 KiB,其他情形以及为解释器验证的程序仍有 512 字节限制,不宜把原文数字理解为所有实现的统一上限。】(Linux 内核 BPF Design Q&A)

这意味着,那些会让传统内核模块崩溃的一类缺陷——空指针解引用、缓冲区溢出和无限循环——从结构上就不可能出现在已加载的 eBPF 程序中。验证器会在测试期间,以及向每台服务器部署时,拒绝不符合要求的程序。

【译者注:上文是作者对验证器设计保证的概括。验证器检查的是规定范围内的程序安全性,不等于证明业务逻辑正确,也不意味着验证器或内核实现本身绝无缺陷。】(Linux 内核 eBPF verifier 文档)

2. 生产前测试

任何 eBPF 变更接触生产流量之前,都要经过全面测试,包括:

  • 虚拟机负载测试:对于竞态条件(race condition)等复杂问题,Cloudflare 会创建虚拟化测试环境,让虚拟机持续接受负载测试,以捕获或复现罕见的竞态条件。
  • VET(Verification and Exhaustive Testing,验证与穷尽测试):变更在接触任何真实流量之前,都要先经过 Cloudflare 专门的生产前测试环境。

3. 通过 Release Manager 分阶段发布

Cloudflare 的 Release Manager 系统是部署用户空间 eBPF 守护进程的主要工具。更新首先部署到金丝雀(canary)数据中心:这些数据中心承载真实客户流量,但不属于主服务器集群。其主要特点包括:

  • 发布持续多天,各发布阶段之间必须等待规定的时间。
  • 每一阶段继续推进之前,都需要获得多重审批。
  • 金丝雀优先:只有在内部环境成功完成测试后,更新才会进入金丝雀站点。这使工程师能够在问题影响全球网络之前发现它们。
  • “持续运行并观察"模式(Soak and Observe):在每个阶段,工程师都会监控对应服务的仪表盘、指标和日志,包括丢包、CPU 使用率、规则编译错误和程序加载错误。每一阶段都有强制规定的最短持续观察时间(soak time),达到后才能继续推进;高风险变更的观察时间更长。

4. 功能门控:将功能启用与二进制部署解耦

对于重大的 eBPF 功能变更,Cloudflare 会使用功能门控(feature gate)。其本质是由发布系统管理的功能开关,用来控制某台服务器是否启用某项功能,而不取决于已部署的二进制版本。这样就可以先在功能关闭的状态下,将新的二进制程序部署到整个服务器集群,再逐步启用功能。

对于 Tubular 这样的关键组件,部署流程按无人值守、故障安全(fail-safe)的要求设计。发布过程一旦失败,必须让先前的版本继续运行,而不能破坏网络连通性。

Cloudflare 使用 bpf_link 将程序挂载到钩子(hook)上。升级程序时,先将新程序加载到内核,再更新现有的 link,使其指向新程序。这一操作是原子的,确保流量要么由旧程序处理,要么由新程序处理,不会出现丢包的空档。部署工具还会校验正在运行的程序的 tag(指令的哈希值),以确保它替换的确实是预期版本。如果 tag 不匹配,工具就会中止更新,防止出现不一致。

6. 平滑重载:二进制程序的零停机升级

用户空间守护进程采用基于 tableflip 的平滑重载机制,由子进程接替父进程,而不中断数据平面。这保证了升级用户空间管理守护进程时,不会影响正在运行的 eBPF 程序,也不会造成丢包。

7. 固定 BPF map:抵御崩溃

用户空间服务通过 bpffs 文件系统(/sys/fs/bpf/、/run/xdpd/bpffs/)中固定的 BPF map,来应对守护进程崩溃和控制平面(control plane)中断。活动套接字绑定、转发表等状态存储在固定到文件系统的 eBPF map 中,使数据的生命周期与用户空间管理进程解耦。

如果用户空间部署工具崩溃或重启,内核中的 eBPF 程序仍会使用保留下来的状态继续运行,不受干扰。如果没有固定的 map,在控制平面中断期间一旦用户空间服务崩溃,物理服务器虽然仍在接收流量,却不再有 XDP/BPF 处理流水线;数据包要么被丢弃,要么出现更糟的情况——全部递交到本机。

8. 配置管理

向数百个站点部署时,需要处理各站点特有的规则,例如不同地区采用不同的 DDoS 规则。Cloudflare 并不为每个站点单独编译二进制程序,而是编译一个代码路径可配置的统一 eBPF 主程序。在某个站点将程序加载到内核之前,先应用配置,启用或禁用特定的逻辑路径。一个二进制程序就能服务整个服务器集群,同时按站点定制。

9. 总结

在大规模、全球分布式环境中运行 eBPF,需要像对待传统内核升级那样严谨地对待 eBPF 程序和 map,同时又要以用户空间部署的节奏快速实施。本文介绍的运维模式,例如依靠验证器的静态分析、通过 bpf_link 执行原子切换,以及利用 BPF 文件系统保留状态,从根本上将数据平面的执行与用户空间守护进程的生命周期解耦。

确保用户空间进程崩溃或版本发布回滚不会中断活动套接字绑定或 XDP 数据包处理后,管理员就能持续、安全地部署内核级逻辑,而不必冒网络分区的风险。构建这套部署机制,是一项历时多年、不断迭代的工程工作。在第六篇文章中,我们将考察这些技术投入的实际回报,用具体的业务、运维和规模扩展指标,量化将网络边缘处理移入内核所带来的收益。

10. 回顾本系列已发布的文章

  • 在第一篇中,我们介绍了 Cloudflare 为什么选择将 eBPF 作为一个平台,而不是一组单点解决方案。
  • 在第二篇中,我们探讨了标准 Linux 网络 API 无法满足 Cloudflare 需求的地方,以及团队为填补这些缺口构建了什么。
  • 在第三篇中,我们介绍了构建 Cloudflare 基于 eBPF 的网络数据路径所需的架构调整,以及向上游贡献代码的工作。
  • 在第四篇中,我们介绍了 Cloudflare 如何利用 eBPF 改善运维能力,包括从头重建可观测性(observability)。

延伸阅读

以下为发布附加的往期推荐,不属于原文系列导航:

  1. Cloudflare 平台重塑:用 eBPF 填补 Linux 生态缺口(中)
  2. Cloudflare 平台重塑:从硬件厂商锁定到可编程网络 eBPF 平台(上)
  3. Cloudflare 平台重塑:落地 eBPF 的技术挑战与五项开创性成果(下)