重磅功能!Apache APISIX 拥抱 WASM 生态
在 Apache APISIX 版本(2.11.0)中,我们新增了对于 WASM 的支持!现在开发者除了可以使用 Lua、Java、Go、Python、JavaScript 等多种编程语言开发 APISIX 的插件之外,也可以用 WASM 来开发插件。
文章图片
WASM 全称 WebAssembly,与上述具体编程语言运行时的不同之处在于,它是一套字节码标准,专门设计成可以在宿主环境中嵌套使用。
如果某种编程语言提供编译成 WASM 字节码的功能,就可以把该语言的应用编译成 WASM 字节码,运行在某个支持 WASM 的宿主环境中。
听起来,是不是只要某个宿主环境支持 WASM,就能像操作系统一样运行任意应用呢?
但其实这里有个限制,就像操作系统需要实现特定标准的 syscall 一样,要想运行特定的应用,也需要实现该应用所需的 API。
以 JavaScript 为例,虽然同样是 JavaScript 代码,但是针对浏览器写的 JS 模块不能直接用在 npm 包里面,因为两个的 API 不一样。
所以仅仅把 WASM 放到 Apache APISIX 里面并行不通,要想让开发者在 Apache APISIX 上运行 WASM,我们还需要提供一套专门的 API。
为什么选择 Proxy WASM
对于如何提供这套 API,我们曾经权衡过两套方案:
- 参考 lua-nginx-module 的接口,实现对应的 WASM 版 API
- 实现 Proxy WASM 这一套标准
WASM API 标准可以拆成两个方面来看:
- Host,负责提供 API 的实现
- SDK,要想在不同的编程语言里面调用提供的 API,需要使用该语言来实现一套胶水层
经过社区的讨论后,我们最终决定采用 Proxy WASM 标准。「做难且正确的事」,实现 Proxy WASM 自然是难的事,但我们相信这是正确的事,通过社区的合作和共建,可以构建更加繁荣的生态。
如何在 Apache APISIX 中使用 WASM Apache APISIX 目前已初步支持 WASM,可以使用 WASM 来编写 fault-injection 插件的部分功能。
下面我们将结合 proxy-wasm-go-sdk 来讲讲怎么用 WASM 实现注入自定义响应的功能。
步骤一:基于 proxy-wasm-go-sdk 编写代码
实现代码(包含
go.mod
和其他)具体细节可参考:https://github.com/apache/api...这里需要解释下,虽然 proxy-wasm-go-sdk 这个项目带了 Go 的名字,但它其实用的是 tinygo 而不是原生的 Go。因为原生的 Go 在支持 WASI (你可以认为它是非浏览器的 WASM 运行时接口)时会有一些问题,详情参考:https://github.com/tetratelab...。
步骤二:构建对应的 WASM 文件
tinygo build -o ./fault-injection/main.go.wasm -scheduler=none -target=wasi ./fault-injection/main.go
步骤三:在
config.yaml
引用该文件apisix:
...
wasm:
plugins:
- name: wasm_fault_injection
priority: 7997
file: t/wasm/fault-injection/main.go.wasm
通过以上操作,你可以像用 Lua 插件一样用这个 WASM 插件,比如:
---
uri: "/wasm"
plugins:
wasm_fault_injection:
conf: '{"body":"hello world", "http_status":200}'
upstream:
type: roundrobin
nodes:
127.0.0.1:1980: 1
注意 WASM 插件的配置都是 conf 字段下面的一条字符串,由对应的插件自己去做解析。
横向测评——条条大道通罗马 Apache APISIX 发展到现在,已经有三种编写插件的方式:
- 原生的 Lua way,跑在 APISIX 里面
- 多种语言的外部插件 runner,插件逻辑跑在 APISIX 外面
- 把多种语言编译成 WASM,依然跑在 APISIX 里面
文章图片
这三种方式在诸如生态、成熟度等各个方面都差异很大。正巧我们都可以用它们来实现 fault-injection,所以可以比比看。
步骤一:配置路由
Lua way 的 fault-injection,自然是使用内置的 fault-injection 插件。Runner way 的 fault-injection 实现具体可参考:https://github.com/apache/api...\_injection.go
让我们分别给它们配置不同的路由:
---
uri: "/wasm"
plugins:
wasm_fault_injection:
conf: '{"body":"hello world", "http_status":200}'
upstream:
type: roundrobin
nodes:
127.0.0.1:1980: 1
---
plugins:
ext-plugin-pre-req:
conf:
- name: fault-injection
value: '{"body":"hello world", "http_status":200}'
upstream:
nodes:
127.0.0.1:1980: 1
type: roundrobin
uri: /ext-plugin
---
plugins:
fault-injection:
abort:
body: hello world
http_status: 200
upstream:
nodes:
127.0.0.1:1980: 1
type: roundrobin
uri: /fault-injection
步骤二:实际压测
接下来试着用 wrk 进行压测,具体数据对比如下:
文章图片
从上述结果可以看到,WASM 版本的性能介于外部插件和原生 Lua 之间。
WASM 版本的性能之所以比外部插件好那么多,是因为 fault-injection 功能简单,所以外部插件 RPC 带来的性能损耗过于明显。考虑到我们还没有对 WASM 实现做任何优化,这种情况已经让我们感到满意了。
而 WASM 的另一个好处,就是让我们一下子拥有多语言的支持(这也托了 Proxy WASM SDK 的福)。具体细节可参考下方文档:
- Rust 版本 fault-injection:
https://gist.github.com/space...
- AssemblyScript 版本 fault-injection:
https://gist.github.com/space...
- 编程语言支持待完善:原生 Go 的 WASM 支持,主要是基于浏览器环境的,所以我们不得不用 tinygo 来实现。但是 tinygo 作为一个年轻的项目,还是有不少局限性。
- Proxy WASM 生态有待成熟: AssemblyScript 版本的 fault injection 实现,并没有 JSON decode 的部分。这是因为 AssemblyScript SDK 是基于 AssemblyScript 0.14.x 版本实现的,而几个开源的 AssemblyScript JSON 库都是针对高版本 AssemblyScript 实现的,没办法用在较为陈旧的 AssemblyScript 0.14 上。
- WASM 没有内置协程: WASM 目前尚未内置协程,所以没办法很好地被宿主的调度系统给调度起来。
- 包括 Apache APISIX 和 Envoy 等开源项目对于 WASM 都很看重,有许多初创公司和大企业为 WASM 生态添砖加瓦,这意味着诸如 AssemblyScript SDK 停滞不前这样的困难,只会是暂时。长久看,Proxy WASM 的生态会枝繁叶茂。
- WASM 作为 serverless 和 edge computing 的宠儿,有着光明的未来。在众多实际场景的落地和优化,会更快的解决技术上的不足。
“千里之行,始于足下”,Apache APISIX 为了支持 WASM,已经发起了 wasm-nginx-module 这个开源项目。感兴趣的读者可以关注该项目的进展,“独行者速,众行者远”,期待你的加入,一起创造世界顶级项目。
活动预告 1 月 15 日,Apache APISIX 社区将联合 Apache ShardingSphere 社区为大家带来主题为 「从网关到数据,分布式全链路在线应用实践」 的线上分享。本次活动不仅邀请了来自两大社区的技术大咖,更有 Apache SkyWalking PMC Chair 吴晟作为特邀嘉宾,为大家揭秘由 Apache APISIX、Apache ShardingSphere、Apache SkyWalking 三大社区联手打造的一款支持全链路压测的工具:CyborgFlow。
众多精彩议题内容等你来看!
文章图片
入群交流 扫描下方二维码添加小助手微信,由小助手邀请您进入 Apache APISIX 在线交流群,了解更多社区动态!
【重磅功能!Apache APISIX 拥抱 WASM 生态】
文章图片
推荐阅读
- Apache多路复用模块(MPMs)介绍
- 分享!如何分分钟实现微信扫二维码调用外部浏览器打开指定页面的功能
- Excel|Excel 2013 新增功能之瞬间填充整列数据!
- springboot结合redis实现搜索栏热搜功能及文字过滤
- 随笔|随笔 心累了
- MQ(消息队列)功能介绍
- 关于iOS录屏功能躺过的坑,给有需要的人
- mac|mac php5.6+mongdb+Apache环境配置
- java|微软认真聆听了开源 .NET 开发社区的炮轰( 通过CLI 支持 Hot Reload 功能)
- 微信视频号iOS端大改版!5个月等待,20+项功能改动了解一下()