首页
/ Envoy Wasm 插件执行架构:扩展点、执行模型与运行时配置全解析

Envoy Wasm 插件执行架构:扩展点、执行模型与运行时配置全解析

2026-09-13 17:27:42作者:仰钰奇

导读

本文基于 Envoy 官方架构文档(wasm.rst)展开,系统讲解 Envoy 如何通过 Proxy-Wasm ABI 执行 WebAssembly 插件:从插件可挂载的五大扩展点,到 Context / Plugin / VM 三大抽象的关系,再到过滤器运行时在主线程与工作线程间的执行与克隆模型,最后深入到 proxy_call_foreign_function 宿主函数、Envoy Attributes 以及 V8 / WAMR / Wasmtime / Null VM 四类运行时。读完本文,你将掌握 Envoy Wasm 插件"写一次、随处运行"的底层原理,并能结合 wasm.protoVmConfigPluginConfig 的字段含义,独立配置与调试 Wasm 过滤器。

一、Wasm 插件与 Proxy-Wasm 规范

Envoy 支持执行 Wasm 插件:这些模块针对 Proxy-Wasm 规范 编写,该规范定义了宿主(Host)与访客(Guest)之间的扩展接口,使模块可以实现自定义的扩展逻辑。当前推荐使用 Proxy-Wasm ABI(Application Binary Interface)版本 0.2.1

Wasm 提供了一种可移植且紧凑的二进制可执行格式,可以从多种语言(如 C++ SDKRust SDK一次编译、随处运行。也就是说,同一份 .wasm 字节码既可以运行在 Envoy 中,也可以运行在其他支持 Proxy-Wasm ABI 的代理(如 Mosn、Nginx 的 wasm 模块等)上,插件开发者无需为每个宿主重新编译或重写业务逻辑。

在 Envoy 仓库中,Wasm 相关的公共代码集中在 source/extensions/common/wasm 目录,其中:

  • wasm.h 定义了 Wasm 类(Wasm 执行实例,管理 Envoy 侧的 Wasm 接口)、WasmHandlePluginHandle
  • wasm_vm.cc 实现了 EnvoyWasmVmIntegration,负责把 Envoy 的日志、错误处理与 Null VM 的宿主函数桥接进 Proxy-Wasm 运行时;
  • foreign.cc 实现了一组 Envoy 扩展的宿主函数(见下文"Foreign functions")。

动手实践:官方在示例项目(envoyproxy/examples)中提供了 wasm-cc sandbox,可参考 Wasm 过滤器配置文档 中展示的 envoy.yaml 示例,了解如何从本地磁盘加载一个 Wasm 二进制并挂载为过滤器。

二、五大扩展点:Wasm 插件可以挂在哪里

Envoy 提供了多个扩展点,Wasm 插件可以在其中被调用:

扩展点 对应 v3 API 消息 作用
HTTP 过滤器 extensions.filters.http.wasm.v3.Wasm 在 HTTP 请求/响应路径上执行插件逻辑
网络层(L4)过滤器 extensions.filters.network.wasm.v3.Wasm 在 TCP 连接层执行插件逻辑
统计接收器(StatsSink) extensions.stat_sinks.wasm.v3.Wasm 将插件作为指标导出通道
访问日志器(AccessLogger) extensions.access_loggers.wasm.v3.WasmAccessLog 用插件自定义访问日志格式与输出
后台服务 extensions.wasm.v3.WasmService 作为独立后台服务运行,不绑定具体请求

Envoy 在插件上具体调用哪些函数,取决于该插件被配置在哪个扩展点上。以 HTTP 过滤器为例:

  • api/envoy/extensions/filters/http/wasm/v3/wasm.proto 中,Wasm 消息只包含一个 config 字段,类型为通用的 envoy.extensions.wasm.v3.PluginConfig
  • source/extensions/filters/http/wasm/config.h 中,WasmFilterConfig 以名称 envoy.filters.http.wasm 注册为 NamedHttpFilterConfigFactory,同时通过 UpstreamWasmFilterConfig 注册为上游 HTTP 过滤器工厂;
  • 注册后,过滤器工厂在创建过滤器链时会把插件同时注册为 stream filter 与 access log handler(见 config.haddStreamFilter(filter)addAccessLogHandler(filter) 的调用),印证了 HTTP 插件可以同时参与请求处理和日志输出。

source/extensions/extensions_metadata.yaml(约第 797 行)可以看到 envoy.filters.http.wasm 的元数据:当前状态标记为 alpha(仍在活跃开发中,能力会持续扩展,配置结构也可能变化),安全姿态(security_posture)标记为 unknown,配置时需结合自身信任模型评估风险。

三、Contexts、Plugins 与 VMs:三个核心抽象

理解 Envoy Wasm 的关键是区分三个概念:

Context(上下文) 指宿主(Envoy)与访客(Wasm 字节码)之间的接口实现。以 HTTP 过滤器为例,存在两类 context:

  • root context(ID 为 0):仅承载配置的上下文,负责接收与处理插件配置;
  • per-request context:每个请求创建一次,承载单次请求的流式回调。

VM(虚拟机) 指一个 Wasm 字节码模块的执行实例:

  • 通过 vm_id 字段可以为同一份字节码创建多个 VM,每个 VM 拥有独立的 per-VM 内存;
  • 反过来,同一个 VM 也可以容纳针对不同扩展(插件)的多个实现,供不同 context 使用。VM 共享 可以优化运行时开销、减小字节码总二进制体积,因为多个扩展可以共享同一份代码。

Plugin(插件) 是连接 context 与 VM 的纽带。它指定:

  • 该 context 使用哪个 Wasm VM;
  • 在 VM 执行实例中调用哪个扩展(通过 PluginConfig.root_id 字段值标识);
  • 在 xDS 更新时,如何把配置调用路由到对应扩展。

在源码层面,plugin.h 中的 Plugin 类把 PluginConfignameroot_idvm_idruntimeconfiguration 等字段组装成 proxy_wasm::PluginBase,并维护 Envoy 侧的 WasmConfig(含允许的能力列表 allowed_capabilities_ 与注入的环境变量 envs_);wasm.h 中的 Wasm 类则通过 getRootContext 按插件找到对应的 root context,实现"Plugin → VM → Context"的寻址链路。

三者的协作关系

PluginConfig (name, root_id, vm_config, configuration)
        │
        ▼
   Plugin ──► 选择/启动 VM (按 vm_id + 代码哈希 共享)
        │
        ▼
  root context (ID=0, 配置回调) ──► per-request context (每个请求一个)

四、过滤器执行模型:主线程加载、工作线程内联执行

运行时的执行模型是理解性能特征的核心:

  1. 运行时:Wasm 模块在工作线程上内联执行(inline),通过 ABI 定义的一系列流式回调(stream callbacks)与 Envoy 交互。工作线程彼此独立,不共享 Wasm 执行实例及其运行时内存。异步或阻塞操作被委托给 Envoy 执行,完成后再由 Envoy 在插件上调用独立的完成回调(completion callback)。

  2. 配置时:Wasm 模块在主线程(main thread)上加载到 Wasm 引擎中。对于"模块二进制 × vm_id"的每种组合,会派生一个独立的 Wasm 执行实例。该实例通过回调接收每个插件的 Wasm 配置——在包含该 Wasm 过滤器的每个 xDS listener 上,这个回调可能被反复触发。如果回调接受配置,主执行实例会被克隆到每个工作线程

  3. 与普通过滤器的关键区别:Wasm 过滤器的配置模型是跨 xDS listener 共享的。普通 HTTP 过滤器为每个 xDS listener 独立实例化,而 xDS listener 们在 xDS 更新期间共享同一个主 Wasm 执行实例。这正体现了上一节"VM 共享降低开销"的设计意图。

从源码看,wasm.h 中的 WasmHandle 实现了 ThreadLocal::ThreadLocalObjectgetOrCreateThreadLocalPlugin 负责为每个工作线程创建/获取线程局部插件句柄;PluginHandleSharedPtrThreadLocal 作为 ThreadLocalObject 存储了每线程的插件句柄与最近加载时间戳(last_load),这与文档描述的"主实例克隆到每个 worker 线程"的执行模型一一对应。

五、Envoy Attributes:通过 proxy_get_property 暴露宿主属性

Wasm ABI 通过专用的 proxy_get_property 接口桩向插件暴露 Envoy 特有的宿主属性。这些就是 Envoy 标准的 Attributes,返回值按照类型进行二进制序列化。

Envoys 的属性命名采用点分隔路径(如 request.path),类型固定(stringint 等),且可能因上下文而存在或缺失。在 Wasm 扩展中,属性值按类型序列化:

  • 字符串(string)与字节(bytes)原样传递;
  • 整数(int/uint)按 64 位直接传递;
  • 时间戳与时长(timestamp/duration)近似为纳秒;
  • 结构化值递归转换为一组键值对。

常用的请求/响应/连接属性包括:

  • 请求属性(仅 HTTP 过滤器可用):request.pathrequest.url_pathrequest.hostrequest.schemerequest.methodrequest.headersrequest.timerequest.idrequest.protocol 等;请求完成后还有 request.durationrequest.sizerequest.total_size
  • 响应属性(仅请求完成后可用):response.coderesponse.code_detailsresponse.flagsresponse.headersresponse.sizeresponse.total_sizeresponse.backend_latency 等;
  • 连接属性source.addresssource.portdestination.addressdestination.portconnection.idconnection.mtlsconnection.tls_version 等。

这些属性同样被 CEL 运行时(如 RBAC 过滤器)使用,因此基于属性的策略(RBAC)与基于 Wasm 的扩展可以共享同一套属性语义。

六、Foreign functions:超越 ABI 的宿主扩展能力

Envoy 在 Proxy-Wasm ABI 之上,通过 proxy_call_foreign_function 二进制接口提供了额外功能。从 foreign.cc 的实现看,这些功能通过 proxy_wasm::RegisterForeignFunction 注册:

函数名 功能 源码佐证
sign 创建密码学签名 通过 importPrivateKey 从 PEM/DER 格式导入私钥(见 foreign.cc 中的 SignArguments 处理)
verify_signature 验证密码学签名 通过 importPublicKey 从 PEM/DER 导入公钥(VerifySignatureArguments
compress 应用 zlib 压缩 foreign.cc 直接引入 zlib.h
uncompress 应用 zlib 解压 同上
declare_property 创建带类型信息的占位 filter state 对象 使用 ext/declare_property.pb.h 消息
set_envoy_filter_state 设置 filter state 对象 使用 ext/set_envoy_filter_state.pb.h 消息
clear_route_cache 更新已选中的路由
expr_create 编译 CEL 表达式供后续求值 WASM_USE_CEL_PARSER 编译开关保护,依赖 eval/public/cel_expr_builder_factory.h 等 CEL 库
expr_evalute 求值已编译的 CEL 表达式 同上(注意原文档中此名称为 expr_evalute,为拼写沿用)
expr_delete 删除已编译的 CEL 表达式 同上

这些函数的正确性有对应的单元测试验证。在 test/extensions/common/wasm/wasm_test.cc 中:

  • Foreign 测试用例验证了 compress/uncompress 行为:对 2000 字节数据压缩后体积约 2x 字节(测试注释说明 zlibzlib-ng 的压缩大小略有差异,因此使用正则匹配 "compress 2000 -> 2[0-9]");
  • OnForeign 测试用例验证了 on_foreign_function 回调,以 713 两个参数调用,期望插件输出 on_foreign_function 7 13

这些测试覆盖了 V8 等真实 Wasm 运行时(加载 test_cpp.wasm)与 Null VM(插件名为 CommonWasmTestCpp)两种路径,印证了 foreign functions 在真实字节码与本地编译两种模式下行为一致。

七、Wasm runtime:V8、WAMR、Wasmtime 与 Null VM

Envoy Wasm 可以通过 VmConfig.runtime 字段配置使用多种 Wasm 运行时实现,只要该运行时包含在 Envoy 发行版中即可:

  • V8envoy.wasm.runtime.v8):基于 Google V8 的 WebAssembly 运行时,是官方构建中默认优先启用的引擎;
  • WAMRenvoy.wasm.runtime.wamr):基于 bytecodealliance wasm-micro-runtime 的运行时,官方构建默认不启用;
  • Wasmtimeenvoy.wasm.runtime.wasmtime):基于 Bytecode Alliance Wasmtime 的运行时,官方构建默认不启用;
  • Null VMenvoy.wasm.runtime.null):特殊的伪 Wasm 运行时,Wasm 插件代码被编译为原生(非 Wasm)代码并静态链接进 Envoy 二进制,因此没有沙箱隔离,主要用于测试与性能对比。

wasm.proto 的注释可以确认运行时选择规则:runtime 默认为 Envoy 构建时可用的第一个 Wasm 引擎,搜索优先级为 v8 → wasmtime → wamr

源码层面,各运行时以扩展工厂形式注册。例如 source/extensions/wasm_runtime/v8/config.cc 中:

  • V8RuntimeFactorycreateWasmVm() 返回 proxy_wasm::createV8Vm()
  • 工厂名称为 envoy.wasm.runtime.v8
  • 通过 #if defined(PROXY_WASM_HAS_RUNTIME_V8) 条件编译,仅在构建时包含 V8 的情况下执行 REGISTER_FACTORY 注册。

类似地,source/extensions/wasm_runtime 目录下还有 wamr/config.ccwasmtime/config.ccnull/config.cc。工厂的统一基类在 wasm_runtime_factory.h 中定义,类别(category)为 envoy.wasm.runtime

Null VM 的使用方式:当使用 Null VM 时,VmConfig.code 字段的 inline_string 中应填写已静态链接进 Envoy 二进制的插件注册名(如测试中的 CommonWasmTestCpp),而非字节码文件。由于代码直接链接进二进制,它不受沙箱保护,仅应在可信环境中使用。

八、配置实战:VmConfig 与 PluginConfig 字段详解

Wasm 的配置入口是 envoy/extensions/wasm/v3/wasm.proto 中定义的 VmConfigPluginConfig。下面结合字段注释逐一展开。

VmConfig:VM 级配置

字段 类型 说明
vm_id string 与 wasm 代码哈希(或 Null VM 插件注册名)共同决定使用哪个 VM。所有使用相同 vm_id 与代码的插件共享同一个 VM,可留空。共享 VM 可降低内存占用、便于数据共享,但也可能带来安全影响
runtime string Wasm 运行时类型,默认取构建时第一个可用引擎(v8 → wasmtime → wamr)
code config.core.v3.AsyncDataSource 要执行的 Wasm 代码,支持本地文件、内联字符串或远程拉取(异步数据源)
configuration google.protobuf.Any 新 VM 初始化(proxy_on_start)时使用的 Wasm 配置。Struct 会序列化为 JSON 后传给插件;BytesValueStringValue 去掉包装直接传递
allow_precompiled bool 是否允许 wasm 文件包含预编译代码。⚠️ 预编译代码不会被校验,仅应对可信来源开启
nack_on_code_cache_miss bool 为 true 且代码需远程拉取但缓存未命中时:NACK 配置更新并在后台拉取填充缓存;否则异步拉取代码并进入 warming 状态
environment_variables EnvironmentVariables 注入 VM 的环境变量,通过 WASI 的 environ_get / environ_get_sizes 系统调用可见(通常由语言标准库隐式调用)。存在键空间冲突时 Envoy 会拒绝配置
capability_restriction_config CapabilityRestrictionConfig 限制模块可用的 Proxy-Wasm 能力,按名称映射 allowed_capabilities。限制在 VM 创建时应用,被该 VM 内所有插件共享,属于 VM 属性而非单个插件属性

EnvironmentVariables 支持两类注入:host_env_keys(从 Envoy 自身环境变量按 key 透传,key 不存在则忽略)与 key_values(显式 KEY=VALUE 键值对)。

CapabilityRestrictionConfig.allowed_capabilities 的能力名称取自 Proxy-Wasm ABI 规范,此外还实现了以下 WASI 能力:fd_writefd_readfd_seekfd_closefd_fdstat_getenviron_getenviron_sizes_getargs_getargs_sizes_getproc_exitclock_time_getrandom_get。每个能力映射到的 SanitizationConfig(输入清洗)目前尚未实现,应保持为空。

PluginConfig:插件级配置

字段 类型 说明
name string VM 内过滤器/服务的唯一名称。当多个过滤器/服务由相同 vm_id + root_id 处理时,用于区分及日志/调试定位
root_id string VM 内一组共享 RootContext 与 Context 的过滤器/服务的唯一 ID。留空时,所有相同 vm_id 下 root_id 为空的过滤器/服务将共享 Context
vm_config VmConfig(oneof vm) 查找或启动 VM 的配置
configuration google.protobuf.Any 用于配置/重配置插件(proxy_on_configure),序列化规则同 VmConfig.configuration
fail_open bool 已废弃(3.0 移除),改用 failure_policy。VM 发生致命错误(异常、abort()on_start/on_configure 返回 false)时,若为 true 则绕过过滤器放行
failure_policy FailurePolicy 插件失败策略(见下文)
reload_config ReloadConfig 仅当 failure_policyFAIL_RELOAD 时生效,配置 VM 失败重载的退避策略
capability_restriction_config CapabilityRestrictionConfig 已废弃(3.0 移除),能力限制属于 VM 级属性,应配置在 vm_config 上;若此处设置而 vm_config 未设置,会用于填充后者
allow_on_headers_stop_iteration google.protobuf.BoolValue 是否允许插件的 onRequestHeaders / onResponseHeaders 回调返回 FilterHeadersStatus::StopIteration

FailurePolicy:VM 失败时的处置策略

wasm.proto 中定义了 FailurePolicy 枚举,在 VM 发生致命错误(如异常、abort())时生效:

  • UNSPECIFIED(0):未指定,使用默认策略,即 FAIL_CLOSED
  • FAIL_RELOAD(1):VM 失败时为新请求创建新的插件实例。注意仅对 proxy_wasm::FailState::RuntimeError 生效,其余失败回退到 FAIL_CLOSED
  • FAIL_CLOSED(2):与该 VM 关联的所有插件返回 HTTP 503 错误(默认行为,失败关闭);
  • FAIL_OPEN(3):忽略与该 VM 关联的所有插件,过滤器链继续执行,适用于插件可选的场景(失败开放)。

ReloadConfig 提供 backoffconfig.core.v3.BackoffStrategy)字段配置失败重载的退避策略,未指定时默认使用 1s 基础间隔。

参考配置骨架

以下是一个 HTTP 层 Wasm 过滤器的最小配置骨架(字段与 PluginConfig 对应,具体键名以实际 proto 为准):

http_filters:
- name: envoy.filters.http.wasm
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
    config:
      name: my_wasm_plugin
      root_id: my_root
      vm_config:
        vm_id: my_vm
        runtime: envoy.wasm.runtime.v8
        code:
          local:
            filename: /path/to/plugin.wasm
        allow_precompiled: false
      configuration:
        "@type": type.googleapis.com/google.protobuf.StringValue
        value: "plugin config string"
      failure_policy: FAIL_CLOSED

完整示例可参考 Wasm 过滤器配置文档 中从本地磁盘加载 Wasm 二进制的配置片段(该文档同时展示了下游与上游两种过滤器配置)。注意该过滤器目前不支持 Windows,且处于实验性阶段(alpha)。

九、小结

Envoy 的 Wasm 支持以 Proxy-Wasm ABI 0.2.1 为契约,把 C++/Rust 等语言编写的扩展编译成可移植字节码,并能在 HTTP 过滤器、网络过滤器、StatsSink、AccessLogger 与后台服务五个扩展点上运行。其核心设计可以概括为:

  • 三层抽象:Context(接口实现)、Plugin(配置与路由纽带)、VM(隔离的执行实例,可按 vm_id 共享);
  • 两阶段执行模型:主线程加载与配置回调 → 接受配置后克隆主实例到各工作线程,运行时内联执行流式回调,阻塞操作委托 Envoy 并在完成回调中收尾;
  • 宿主能力扩展:通过 proxy_get_property 暴露标准 Attributes,通过 proxy_call_foreign_function 提供签名、压缩、CEL 表达式与 filter state 等十项增强功能;
  • 多运行时可选:V8(默认优先)、Wasmtime、WAMR 以及无沙箱的 Null VM,均以 envoy.wasm.runtime.* 扩展工厂注册;
  • 精细化失败控制FailurePolicy 提供 FAIL_CLOSED / FAIL_OPEN / FAIL_RELOAD 三级策略,配合能力限制与重载退避,让插件故障可控。

无论是出于性能对比、功能扩展还是安全加固,理解上述模型都能帮助你更准确地判断 Wasm 插件在 Envoy 中的行为边界与配置取舍。更深入的 API 字段细节,可继续查阅 wasm.proto 及对应扩展点(HTTP、Network、StatsSink、AccessLog、Bootstrap)的 proto 与源码实现。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
34
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.21 K
2.81 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
945
1.86 K
docsdocs
暂无描述
Markdown
906
5.84 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
537
607
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
864
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
4.28 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.39 K
1.48 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
550
401
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.19 K
347