背景信息
2019年前,Envoy是以静态编译的二进制文件方式来运行的,这意味着其所有扩展等均需要在构建阶段完成编译。因此其他工程(例如Istio)只能发布他们自己维护的自定义Envoy版本,一旦有更新或者Bug修复就不得不构建一个新的二进制版本、发布、重新部署到生产环境中。
上述问题虽然没有一个完美的解决方案,但是部分场景下可以通过C++的动态可加载性来实现,即在一种标准的二进制应用接口(ABI, Application Binary Interface)下编写、交付WebAssembly(WASM)模块,
WASM 本身是源自前端的技术,是为了解决日益复杂的前端 Web 应用以及有限的 JS 脚本解释性能而诞生的技术,通过该技术可以使用非 JavaScript 编程语言编写代码并且能在浏览器上运行。
随着WASM的发展,现在WASM不仅仅可以用于浏览器, 它已经被定义为一个可移植、体积小、加载快并且兼容 Web 的全新格式为一种可移植的二进制格式。
本文讨论的WASM用于以接近本机的速度在一个内存安全(memory-safe)的沙箱中执行多种语言编写的代码,在沙箱内有明确的资源限制和API来与内嵌的主机环境(例如Envoy)通信。
优点
-
敏捷性:WASM可以动态加载到正在运行的Envoy进程中,而无需停止或重新编译
-
可维护性:不必更改Envoy自身基础代码库即可扩展其功能
-
多样性:可以将流行的编程语言(例如C/C++和TinyGo)编译为WASM,因此开发人员可以选择实现过滤器的编程语言
-
可靠性和隔离性:过滤器会被部署到VM沙箱中,因此与Envoy进程本身是隔离的;即使当WasmFilter出现问题导致崩溃时,它也不会影响Envoy进程
-
安全性:过滤器通过预定义API与Envoy代理进行通信,因此它们可以访问并只能修改有限数量的连接或请求属性
缺点
-
内存消耗:WASM虚拟机的使用将锁定使用一部分内存
-
性能损耗:报文数据在沙箱内外进行拷贝与转码
Proxy-wasm
Proxy-Wasm是WASM扩展模块与L4/L7代理之间的二进制应用接口(ABI)规范与标准,其明确定义了主机环境与Wasm虚拟机之间、函数调用、内存管理等通信接口。
当前Proxy-wasm提供了AssemblyScript SDK、C++ SDK、Go (TinyGo) SDK、Rust SDK、Zig SDK SDK,支持Envoy、Istio Proxy (Istio基于Envoy的扩展)、MOSN等代理主机环境中运行。
整体架构
在每个Envoy工作线程上(事件驱动),内置的WASM运行时将创建一个Wasm虚拟机,通过Proxy-Wasm
规范来校验、实例化WASM模块(本地磁盘文件或控制面板XDS推送的方式)。
WASM模块通过扩展接口进行调用时,Proxy-Wasm
通过一个垫片进行转码、翻译在Wasm虚拟机上运行。
注: Envoy 使用单进程 - 多线程
的架构模型。一个 master 线程管理各种琐碎的任务,而一些 worker 线程则负责执行监听、过滤和转发。当监听器接收到一个连接请求时,该连接将其生命周期绑定到一个单独的 worker 线程。
运行时
Envoy内嵌了基于LLVM的WAVM
与V8
两个C/C++ Wasm 运行时,在WASM模块配置时可进行选择。
Proxy-wasm-go-sdk
Go (TinyGo) SDK是一种基于Tinygo语言的Proxy-Wasm
实现。
本文基于该项目标签v0.14.0
进行阐述。
TinyGo
TinyGo是一个Go编译器,旨在用于微控制器,WebAssembly(WASM)和命令行工具等小型场景。它重用了Go语言工具和LLVM一起使用的库,以提供编译用Go编程语言编写的程序的另一种方法。
官方的Go编译器无法产生Proxy-Wasm
所兼容的二进制文件,并且TinyGo相比较于Go另一个最主要的的差异是二进制尺寸。
根据TinyGo官方描述,最简单的"Hello world"程序,在strip
命令加持下(移除所有符号标志与调试信息),Go编译器产生837kb大小的二进制,而TinyGo则为10kb,接近于1%的尺寸缩减效率。
使用TinyGo也存在一些限制和约束:
-
部分Go库不可用(可导入,但运行时异常)
-
部分系统调用不可用,如crypto/rand包
-
不支持反射
-
部分语言特性不支持,如
recover
和goroutine
虽然不支持创建协程,但是Proxy-Wasm
定义了OnTick
函数,类似于定时器触发函数,可用于处理一些异步调用任务。
术语
-
虚拟机(Wasm VM): Envoy中Wasm虚拟机是在每个工作线程中被创建的,并且相互之间隔离
-
插件(Plugin): Envoy中的过滤器类型(Http Filter, Network(Tcp) Filter, 和 Wasm Service)。每个扩展模块都可以进行配置,单个虚拟机中相同的Wasm模块经过不同的配置便形成了多个插件
-
Http Filter: 在工作线程虚拟机中处理HTTP协议,可操作Http请求的头、正文、尾部内容
-
Network Filter: 在工作线程虚拟机中处理Tcp协议,可操作Tcp数据帧,连接信息
-
Wasm Service: 运行于Envoy主线程的单例虚拟中,可用于并发处理一些额外的任务如集成metrics,日志等
-
Envoy配置
Envoy中Wasm过滤器配置如下:
vm_config:
vm_id: "foo"
runtime: "envoy.wasm.runtime.v8"
configuration:
"@type": type.googleapis.com/google.protobuf.StringValue
value: '{"my-vm-env": "dev"}'
code:
local:
filename: "example.wasm"
configuration:
"@type": type.googleapis.com/google.protobuf.StringValue
value: '{"my-plugin-config": "bar"}'
字段 | 描述 |
---|---|
vm_config |
配置Wasm虚拟机 |