Apache APISIX 拥抱 WASM 生态

2022年01月14日 阅读数:1
这篇文章主要向大家介绍Apache APISIX 拥抱 WASM 生态,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

在 Apache APISIX 版本(2.11.0)中,咱们新增了对于 WASM 的支持!如今开发者除了可使用 Lua、Java、Go、Python、JavaScript 等多种编程语言开发 APISIX 的插件以外,也能够用 WASM 来开发插件。node

图片

WASM 全称 WebAssembly,与上述具体编程语言运行时的不一样之处在于,它是一套字节码标准,专门设计成能够在宿主环境中嵌套使用。nginx

若是某种编程语言提供编译成 WASM 字节码的功能,就能够把该语言的应用编译成 WASM 字节码,运行在某个支持 WASM 的宿主环境中。git

听起来,是否是只要某个宿主环境支持 WASM,就能像操做系统同样运行任意应用呢?github

但其实这里有个限制,就像操做系统须要实现特定标准的 syscall 同样,要想运行特定的应用,也须要实现该应用所需的 API。web

以 JavaScript 为例,虽然一样是 JavaScript 代码,可是针对浏览器写的 JS 模块不能直接用在 npm 包里面,由于两个的 API 不同。apache

因此仅仅把 WASM 放到 Apache APISIX 里面并行不通,要想让开发者在 Apache APISIX 上运行 WASM,咱们还须要提供一套专门的 API。npm

为何选择 Proxy WASM

对于如何提供这套 API,咱们曾经权衡过两套方案:编程

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

  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: 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/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 在线交流群,了解更多社区动态!

图片