一、引言
本文主要介绍基于 wasmcloud 的分布式开发概念和流程。通过以 wasm 为最小单元的开发,充分适用于当前的分布式开发环境。引用官方文档的原文来说:
Congratulations! You’ve successfully created and run your first actor. Welcome to the world of boilerplate-free, simple distributed application development in the cloud, browser, and everywhere in between.
在了解和探索的过程中,主要参考官方文档进行了相关的示例程序编写和运行,用到的相关材料罗列如下:
说明 | 网址 |
---|---|
官网开发指引 | https://wasmcloud.dev/app-dev/ |
官方examples代码 | https://github.com/wasmCloud/examples |
官方providers列表 | https://github.com/wasmCloud/capability-providers |
官方interfaces列表 | https://github.com/wasmCloud/interfaces |
wasmcloud平台代码 | https://github.com/wasmCloud/wasmcloud-otp |
rust权威指南 | https://zh.b-ok.cc/book/17931171/7b822e |
elixir教程 | https://pragprog.com/titles/passelixir/programmer-passport-elixir/ |
OTP教程 | https://pragprog.com/titles/passotp/programmer-passport-otp/ |
二、基本概念梳理
在展开介绍 wasmcloud 的应用开发之前,我们需要熟悉其抽象出的几个概念。
无论是采用传统的单体应用开发模式,还是微服务开发模式,亦或是 wasmcloud,其解决的问题基本类似,只不过不同的模式下称呼不同而已。
一般而言,应用的开发都可以划分为以下几个部分:
- 纯业务逻辑。*如:商品功能,会员功能等。面向业务开发人员。*
- 中间件。*如:数据库中间件,缓存中间件,流量控制等。面向中间件开发人员,或平台开发人员。*
- 运行环境。*根据不同的技术栈,有不同的运行环境,属于基础设施层。比如采用容器部署的,一般运行在k8s里,这部分面向平台开发人员。*
在 wasmcloud 中具有相似的概念,这里列举如下
概念 | 面向人员 | 说明 |
---|---|---|
actor | 业务开发 | 编写业务逻辑的地方,如果涉及到非业务逻辑的公共能力(或中间件能力),通过引用interface的方式来获取能力。业务人员可使用rust或tinyGo来开发actor。 |
interface | 中间件或平台开发 | 采用CDD模式开发,定义一些业务无关的公共能力接口,比如:keyvalue能力,但是不提供具体的实现。可以在 interface 中定义允许的操作(operations),以及各种结构体(structure)。使用 smithy IDL 进行 interface 的定义,使用 wash 工具来生成对应代码。 |
provider | 中间件或平台开发 | 实现interface的能力,比如同样对于keyvalue功能,可以有redis实现,也可以有vault实现。并且可以用不同的技术栈来实现。可使用 rust 来进行 Provider 开发,官方未来会支持 Go。 |
link def | 业务开发或部署人员 | 由于actor只是引用了具体的interface,并没有指定哪一个provider,所以在实际部署时,需要关联actor和provider。可以通过 wasmcloud shell(wash)命令行,或者平台进行操作。 |
wasm host | 中间件或平台开发 | 作为整个wasmcloud生态的运行基石,用于协调actor,provider之间的分布式通信,同时也提供分布式调度能力。采用 Elixir/OTP 技术栈实现。 |
整体的关系图梳理如下:
wasmcloud app 的开发采用 CDD(Contract Driven Develop) 方式进行,其中 interface 就是契约的定义。
三、开发流程
如果我们需要实现一个全新的业务场景,需要进行以下几个步骤:
)接下来以 kvcounter 为例,进一步说明各个环节。
## 示例目标:
开发一个 kvcounter 示例程序,当用户访问 http://localhost:8080 时,能够正常显示 counter,且每次访问 +1。
示例效果如下:
)
## 1、创建(或使用)interface
在本示例中,我们用到了 kv 功能,所以需要找到一个能够提供 keyvalue 功能的 interface。有两种方式,一是找到一个现成可用的interface,二是定义一个keyvalue 的 interface。
这里以定义一个新的 keyvalue 为例。
### 1.1 使用 wash 工具创建新的 interface
1 | wash new interface keyvalue |
1.2 编写 interface,即:smithy 文件
首先确定该接口提供的操作,然后是每个操作(operations)涉及到的结构体(structure):
这里摘除主要的operation定义,完整的定义可参考链接:
interfaces/keyvalue.smithy at main · wasmCloud/interfaces
1 | // key-value.smithy |
我们看到 smithy 文件只定义了相关的接口,并不涉及到具体的实现。这也是 wasmcloud app开发中比较重要的概念。
actor只依赖于具体的interface,而一个interface可以由多个provider来实现。
对于本示例,同样是 wasmcloud:keyvalue
的契约,我们可以用 redis 技术栈来实现一个 provider,也可以用 vault 来实现。实际上官方提供了两个版本 provider 的实现:
https://github.com/wasmCloud/capability-providers
)### 1.3 生成代码,发布到对应的仓,方便actor开发人员使用
我们可以直接执行 make 指令,生成对应的代码。之后可以把 interface 发布到 crate.io。
Go语言同理,这样在实际开发 actor 时,就可直接引入使用。
## 2、开发 provider
根据官方的说法,provider的作用如下:
启动后,通过 stdio 和 host 进行交互,其主要作用包括:健康检查、通过 RPC 和 actor 交互等。
> Creating a capability provider involves creating a native executable. All capability provider executables have the same basic requirements:
>
> - Accept a Host Data structure from
stdin
immediately upon starting the executable. The host data is a base64 encoded JSON object with a trailing newline making it easy to pull from the stdin
pipe.> - Accept linkdef messages according to the RPC protocol
> - Communicate with actors via rpc messages defined by a capability contract
> - Respond to periodic health checks
)
### 2.1 使用 wash 新建 provider
通过 wash 指令,可以生成 provider 的模板代码
1 | wash new provider kvredis |
2.2 编写 provider
重点是基于 redis 实现 interface 中定义的各种 operations,完整代码见链接,核心代码框架摘录如下:
capability-providers/main.rs at main · wasmCloud/capability-providers
1 |
|
除了基于 redis 实现 provider 外,官方还提供了基于 valut 的 keyvalue 实现,可参阅
capability-providers/main.rs at main · wasmCloud/capability-providers
其中也是有诸如 increment, del, set, get 的实现,而这些 operation 都是在名为 wasmcloud:keyvalue
的契约中定义的。
2.3 生成 provider 产物
简单的使用 make
指令即可完成部署产物,该产物可以推送至 OCI 仓库以方便使用。
3、开发 actor
3.1 新建 actor
使用 wash 指令可以很方便的生成便于快速开发的模板代码:
1 | wash new actor kvcounter |
3.2 开发 actor
声明契约依赖
kvcounter 依赖了两个 interface,用来提供两个能力:httpserver能力和 kv 存储能力。
我们需要声明该依赖,这样打包完成 kvcounter 后,可以 inspect 出对应的信息。
)所以我们需要修改 makefile 的 CLAIMS 信息:
1 | # examples/actor/kvcounter |
使用 interface
根据不同语言,我们可以引入不同的 interface package。以 rust 为例,官方的 interface 可以在 crates.io 中查阅
)我们可在 cargo.toml 中加入 kvcounter 所依赖的两个包:
1 | [package] |
在 actor 中调用:
1 |
|
3.4 打包
我们可以使用 make 指令,将代码打包为 .wasm 文件,进而推送到 OCI 仓库。
4、部署
我们可以使用 wasmcloud shell(即 wash) 或者 web dashboard 进行部署。主要进行如下操作:
- start actors。将 actor 的 wasm 文件上传到 wasmcloud 运行时,或者提供 registry 地址供其下载。
- start providers。将 provider 的包上传到 wasmcloud 运行时,或提供 registry 地址供其下载。
- 建立 link 关系。
在平台的操作截图效果如下:
)这里需要注意的是,kvcounter 的 actor 需要分别与 httpserver 以及 kvredis 的 provider 进行 link,也就是有两条 link 记录。
## 5、访问
至此,已能正常通过 http 进行访问。
1 | ➜ ~ curl localhost:8080 |
NEXT
本文主要是梳理了 wasmcloud app 开发的概况,包括其主要涉及的概念、工具链的使用、主要的开发流程。
在当前的探索过程中,已基本熟悉 wasmcloud 的外围生态,能够根据实际的工作需求,进行部分平台数据获取(或UI)的修改,同时提交 PR,参与官方的平台建设。
下一步需要进一步探究 wasmcloud runtime 的具体实现,尤其是如何调度 actor, provider,以及 actor 和 provider 之间的协作通信细节。