-10 +

ebpf 今日头条 4

今日头条系列 4, 这些特性是在 2021 年 2 月份的。

The Kernel Side

这个月 kernel 5.12 版本添加的新特性:

Did You Know? Program size limit

你是否直到 eBPF 程序限制的最大大小是多少呢? 你可能听过说 eBPF 被限制最多 4K 个指令,这个在早前做出了修改。

eBPF 程序的一个特性性是:在程序加载时,这个程序会被 kernel 强制校验,这个对于保证 kernel 稳定行和低延时是非常必要的。 如果允许长时间的 eBPF 程序将大大降低 kernel 的运行性能。如果 eBPF 程序中存在死循环,这个可能会使得 kernel hang 住。

为了避免这种情况,kernel 校验器会为可执行的路径构建一个有向无环图(DAG), 确保每一个循环都是能够终止的。某些时候可能会存在一些分支重叠的情况,在某些的条件下,校验器会在第一次校验的时候,跳过这个校验。 这个称作 state pruning,如果没有这个机制,大量的指令下这个校验会非常到,导致加载非常慢,可能这个加载时间不能接受。

介绍 eBPF 时,有两个限制性的参数:

第二个限制性参数代表了如果校验器检查指令的次数超过了这个数,这个 eBPF 程序将被拒绝加载。 你可以认为,这个是所有可执行路径的总和减去在分支路径上的修剪数。 如果一个程序的逻辑分支非常复杂,这个将需要校验更多的校验次数,即使程序的指令的决定数量少于 4K 也可能导致加载失败。

上面的两个限制在 Linux 5.2 中做出了改变。 复杂性限制参数被增加到 100 万个指令。这样最大指令数的限制也被简单的消除了。 这样程序的最大大小由 complexity 决定。程序最大指令数最大是 100万,这是一个硬性限制(如果没有任何 if 和 比较), 实际上,这样的程序应该是不会存在的。程序拥有更多的分支,那么校验器就会更加复杂,那么运行的指令数量响应也会降低。

事实上 4096 个指令数量的限制没有消失,如果用户 eBPF 程序是通过 non-root(更加准确的说是,用户没有使用 CAP_SYS_ADMIN, 或者 CAP_BPF kernel version >= 5.8 ) 加载.

eBPF 程序的趋势是变得更加小,100 万个状态复杂性对于绝大数程序应该是足够的。 在一个高级项目中实现非常复杂的程序可能需要适配它,像 cilium 这样的项目就会定期适配校验器的要求。 有效突破复杂性的校验的方式包括 tail calls 和 bounded loops (Linux 5.3 引入), 通过减少分支数量和校验器可以有效裁剪分支的重构代码也是一种有效方式。

硬件卸载又是另外一种方式了,因为程序需要适配硬件的内存,所有它具有完全不同约束。 这个边界又硬件能力和校验器共同设置,字节码的生成效率和 JIT 的执行效率共同发挥作用。

新的百万状态复杂性限制应该可以适合绝大部分的情况,最后程序可能确实存在一个限制:你的想象力!

关于我

85 后程序员, 比较熟悉 Java,JVM,Golang 相关技术栈, 关注 Liunx kernel,目前痴迷于分布式系统的设计和实践。 研究包括但不限于 Docker Kubernetes eBPF 等相关技术。

Blog

Code

Life

Archive