写点什么

重磅功能!Apache APISIX 拥抱 WASM 生态

  • 2022 年 1 月 11 日
  • 本文字数:3225 字

    阅读完需:约 11 分钟

重磅功能!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,我们曾经权衡过两套方案:


  1. 参考 lua-nginx-module 的接口,实现对应的 WASM 版 API

  2. 实现 Proxy WASM 这一套标准


Proxy WASM 是 Envoy 的 WASM API 标准。所以上述问题其实等价于,我们是自己搞一套 API 标准还是复用 Envoy 已有标准呢?


WASM API 标准可以拆成两个方面来看:


  1. Host,负责提供 API 的实现

  2. SDK,要想在不同的编程语言里面调用提供的 API,需要使用该语言来实现一套胶水层


如果我们遵循 Envoy 的标准,优势在于可以复用 Envoy 现有的 WASM SDK(Proxy WASM SDK),而不足之处在于这套标准是 Envoy 结合自己情况制定的,如果我们跟着实现,没有自己量身定制那么轻松。


经过社区的讨论后,我们最终决定采用 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/apisix/tree/master/t/wasm


这里需要解释下,虽然 proxy-wasm-go-sdk 这个项目带了 Go 的名字,但它其实用的是 tinygo 而不是原生的 Go。因为原生的 Go 在支持 WASI (你可以认为它是非浏览器的 WASM 运行时接口)时会有一些问题,详情参考:https://github.com/tetratelabs/proxy-wasm-go-sdk/blob/main/doc/OVERVIEW.md#tinygo-vs-the-official-go-compiler


步骤二:构建对应的 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 发展到现在,已经有三种编写插件的方式:


  1. 原生的 Lua way,跑在 APISIX 里面

  2. 多种语言的外部插件 runner,插件逻辑跑在 APISIX 外面

  3. 把多种语言编译成 WASM,依然跑在 APISIX 里面



这三种方式在诸如生态、成熟度等各个方面都差异很大。正巧我们都可以用它们来实现 fault-injection,所以可以比比看。


步骤一:配置路由


Lua way 的 fault-injection,自然是使用内置的 fault-injection 插件。Runner way 的 fault-injection 实现具体可参考:https://github.com/apache/apisix-go-plugin-runner/blob/master/cmd/go-runner/plugins/fault_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: roundrobinuri: /ext-plugin---plugins:  fault-injection:    abort:      body: hello world      http_status: 200upstream:  nodes:    127.0.0.1:1980: 1  type: roundrobinuri: /fault-injection
复制代码


步骤二:实际压测


接下来试着用 wrk 进行压测,具体数据对比如下:



从上述结果可以看到,WASM 版本的性能介于外部插件和原生 Lua 之间。


WASM 版本的性能之所以比外部插件好那么多,是因为 fault-injection 功能简单,所以外部插件 RPC 带来的性能损耗过于明显。考虑到我们还没有对 WASM 实现做任何优化,这种情况已经让我们感到满意了。


而 WASM 的另一个好处,就是让我们一下子拥有多语言的支持(这也托了 Proxy WASM SDK 的福)。具体细节可参考下方文档:


  • Rust 版本 fault-injection:

  • https://gist.github.com/spacewander/0357198ea21e022003c407fd23155f79

  • AssemblyScript 版本 fault-injection:

  • https://gist.github.com/spacewander/64773a706f1dc758aecc7f28aff7555d

道路曲折,但前途光明

说了这么多 WASM 的好处,是不是有点心动呢?但它目前并非是一个完美的解决方案, WASM/Proxy WASM 还是有一些不够成熟的地方。比如:


  • **编程语言支持待完善:**原生 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 目前尚未内置协程,所以没办法很好地被宿主的调度系统给调度起来。


虽然上面列举了几点不足之处,但是我们相信这个技术栈的前景是光明的:


  1. 包括 Apache APISIX 和 Envoy 等开源项目对于 WASM 都很看重,有许多初创公司和大企业为 WASM 生态添砖加瓦,这意味着诸如 AssemblyScript SDK 停滞不前这样的困难,只会是暂时。长久看,Proxy WASM 的生态会枝繁叶茂。

  2. WASM 作为 serverless 和 edge computing 的宠儿,有着光明的未来。在众多实际场景的落地和优化,会更快的解决技术上的不足。

写在最后

Apache APISIX 是个紧跟技术潮流的项目,“好风凭借力,送我上青天”,Apache APISIX 支持 WASM 是个长期的过程。


“千里之行,始于足下”,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 在线交流群,了解更多社区动态!



用户头像

Github:https://github.com/apache/apisix 2021.06.02 加入

Apache APISIX 是一个云原生、高性能、可扩展的微服务 API 网关。它是基于 OpenResty 和 etcd 来实现,和传统 API 网关相比,Apache APISIX 具备动态路由和插件热加载,特别适合微服务体系下的 API 管理。

评论

发布
暂无评论
重磅功能!Apache APISIX 拥抱 WASM 生态