Envoy网关里的权限判断,现在有个更轻的答案。

API网关、服务网格边界、L7检查点——这些场景都需要一个"放行/拦截"的决策层。默认方案是用OPA的wasm版本,但问题很明显:Go运行时、Rego解析器、执行器全打包进去,体积膨胀几十倍。你只想在边缘返回0或1,却得拖着一个完整的语言运行时。

打开网易新闻 查看精彩图片

Cedar和Casbin至今没有官方wasm构建(截至2026年5月)。"即插即用的proxy-wasm授权过滤器"这个位置,一直是空的。

作者用Zig填上了这个空。zopa是一个wasm32-freestanding二进制文件,release版本约60 KB。没有垃圾回收,内存按请求周期在arena里周转。任何实现了proxy-wasm 0.2.1的主机都能跑——Envoy、wasmtime、wamr、v8。

关键设计决策只有一个:把策略编写和策略执行彻底分开。

策略作者用Rego(OPA的策略语言,Datalog家族的声明式DSL)写规则。CI流程把它转成AST(抽象语法树)JSON。Envoy启动时,AST作为插件配置传给wasm模块;每个请求进来,zopa直接执行AST,返回1或0。

OPA wasm之所以臃肿,是因为解析器执行器绑在一起。zopa把解析器踢出wasm(放进CI任务),让wasm模块只干执行这一件事。仅此一项,二进制体积就下降了数量级。

proxy-wasm是Envoy等工具采用的"wasm过滤器"ABI规范。zopa实现的是0.2.1版本。

体积控制来自三个对立选择:OPA带Go运行时(带GC)、带解析器、带执行器;zopa在每条上都选了反面。结果是60 KB。

内存布局是核心。两个分配器,生命周期和职责不同。

host_allocator是Zig标准库的std.heap.wasm_allocator,自由列表风格,支撑所有跨主机边界的缓冲区。生命周期贯穿整个模块。

request_arena是std.heap.ArenaAllocator,每请求的临时空间。evaluate()结束时调用reset(.retain_capacity)。

arena的意思是"随便分配,结束一起清"。没有单独的free调用。retain_capacity让wasm线性内存页不归还,下个请求复用现有容量。

实际效果:预热完成后,memory.grow(wasm堆增长指令)不再触发。吞吐量上去,内存保持平稳。这就是那个特性的来源。

唯一铁律:一个分配器铸造的指针,只能由同一个分配器释放。