本文 demo 了终端用户以及机器用户如何在只使用 HTTP 请求的状况下,经过 web 从 Wasm 函数中找到答案。 对于更喜欢冒险的读者,本文还 demo了如何在相同的基础结构上编写和部署 Wasm 可执行文件。linux
在以前的文章,咱们谈到,虽然 Wasm 在客户端确实很受欢迎,但 Wasm 最近也成为了服务器端技术和服务的有力竞争者。git
基于这个想法,《去中心化计算的将来:经过 RPC 从微服务过渡到 WASM》一文提出:将来,分布式计算微服务将会由传统的微服务向 Wasm 基础设施过渡。 这其中的缘由有不少。 其中之一就是,经过 Wasm ,在大多数源代码语言和本地硬件之间能够编写和共享单独的 discrete 函数的逻辑。github
所以,不可避免地,这意味着 Wasm 将适用于大多数应用程序,即便 Wasm 在后端,也能够有效地执行一组管理良好的 discrete 函数来为每一个应用程序服务。web
固然,这种乌托邦式的分布式计算模式须要一些基础,咱们能够在这样的基础上创建本身的定制业务和企业软件。macos
虽然咱们的目标看似高不可攀,但其实是能够实现的。在服务端的 WebAssembly 领域,出现了一些使人无比激动的,可以为咱们“铺路”的基础设施。编程
Second State 最近构建了一套软件,使部署和执行服务器端的 Wasm 变得很是方便。json
下面的图表显示了构成这个系统的一些组件,即:后端
Second State 研发的 SSVM 有一个核心的优点,就是使用者不须要知道它的内部工做机制。事实上,要使用 SSVM 执行服务器端的 Wasm,您只须要发出一个简单的 HTTP 请求。浏览器
下文将演示“调用应用程序的函数” ,但在此以前,让咱们先花几分钟的时间进行一次快速的技术深刻讨论。安全
本节将展现如何在 SSVM 上建立和部署本身的 Wasm 可执行文件。咱们将在 Ubuntu 操做系统上使用 Rust,建立和部署 Demo。
sudo apt-get update sudo apt-get -y upgrade curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source $HOME/.cargo/env
cd ~ cargo new --lib add cd add
将如下内容添加到 Cargo.toml 文件
[lib] name = "add_lib" path = "src/lib.rs" crate-type =["cdylib"]
打开新文件 src/lib.rs
并加上如下代码
#[no_mangle] pub extern fn add_two_numbers(_x: i32, _y: i32) -> i32{ _x + _y }
rustup target add wasm32-wasi rustup override set nightly
cargo build --release --target=wasm32-wasi
上面的集合将在 target/wasm32-wasi/release/add_lib.wasm
建立新的Wasm文件。这个文件咱们将部署在 SecondState 的 Wasm 基础设施 SSVM 上。
在部署这个应用程序时,咱们将遵循这个特定的 HTTP POST 规范。
若是想查看新建立的 Wasm 应用程序的文本表示(称为“ WebAssembly Text format”或简称“ WAT”) ,安装很是有用的 WABT工具包就能够。
只需运行如下命令,就能够将 Wasm 转换为 Wat。
./wasm2wat ~/add/target/wasm32-wasi/release/add_lib.wasm -o ~/add/target/wasm32-wasi/release/add_lib.wat
文本展现(WAT) 将大概以下:
(module (type (;0;) (func (param i32 i32) (result i32))) (func $add_two_numbers (type 0) (param i32 i32) (result i32) local.get 1 local.get 0 i32.add) (table (;0;) 1 1 funcref) (memory (;0;) 16) (global (;0;) (mut i32) (i32.const 1048576)) (global (;1;) i32 (i32.const 1048576)) (global (;2;) i32 (i32.const 1048576)) (export "memory" (memory 0)) (export "__data_end" (global 1)) (export "__heap_base" (global 2)) (export "add_two_numbers" (func $add_two_numbers)))
您将注意到原始的 add_lib.wasm
没法随意查看, 由于它是一个可执行的二进制文件。 此外,在没有任何优化的状况下,默认由 Rust 编译生成 Wasm 文件大约为1800000字节。 就Wasm而言,这是很大的。
咱们将使用 xxd
命令将 Wasm 文件转换为十六进制(用于 HTTP POST 的 JSON 数据)。 可是,我建议在转换以前,缩小原来的 Wasm 文件。
xxd -p target/wasm32-wasi/release/add_lib.wasm | tr -d $'\n'
缩小 Wasm 可执行文件的一个很是简单的方法是再次使用超赞的 wabt toolkit * 。 除了在这里,咱们还将以另外一种方式转换回来,即,将刚刚建立的 wat 文件转换回 wasm,以下所示。
./wat2wasm ~/add/target/wasm32-wasi/release/add_lib.wat -o ~/add/target/wasm32-wasi/release/add_lib.wasm
如今能够安全地执行上面的 xxd
命令了。
这些 wabt 转换的整体结果是, Wasm 可执行文件的大小从以前的 1800000字节变为 4000字节。 新的 Wasm 可执行文件的十六进制表示形式(在 xxd 命令以后)如今看起来像这样(仅供参考)。
0061736d0100000001070160027f7f017f030201000405017001010105030100100619037f01418080c0000b7f00418080c0000b7f00418080c0000b073704066d656d6f727902000a5f5f646174615f656e6403010b5f5f686561705f6261736503020f6164645f74776f5f6e756d6265727300000a09010700200120006a0b
复制粘贴很容易了,对吗?
Wasm 文件的这个十六进制转储须要一个小调整。 在部署应用程序以前,咱们须要在 Wasm 十六进制字符串的开头添加一个 0x
。
下面是咱们如何经过 Curl 部署上面的 Wasm 应用程序的示例。
注意咱们手动添加的 0x
,在字节码的开头!
curl --header "Content-Type: application/json" \ --request POST \ --data '{ "request": { "application": { "storage": "file_system", "bytecode": "0x0061736d0100000001070160027f7f017f030201000405017001010105030100100619037f01418080c0000b7f00418080c0000b7f00418080c0000b073704066d656d6f727902000a5f5f646174615f656e6403010b5f5f686561705f6261736503020f6164645f74776f5f6e756d6265727300000a09010700200120006a0b","name": "Add"}}}' \ http://13.54.168.1:8080/deploy_wasm_application
若是使用 GUI HTTP 客户机发出 POST 请求,那么下面是您传入的等效 JSON。
一样,请注意咱们在字节码开始时手动添加的 0x
!
{ "request": { "application": { "storage": "file_system", "bytecode": "0x0061736d0100000001070160027f7f017f030201000405017001010105030100100619037f01418080c0000b7f00418080c0000b7f00418080c0000b073704066d656d6f727902000a5f5f646174615f656e6403010b5f5f686561705f6261736503020f6164645f74776f5f6e756d6265727300000a09010700200120006a0b", "name": "Add" } } }
{"response":{"application":{"name":"Add","uuid":"0xa9d57ac0f5046512"},"status":"success"}}
当应用程序部署时,将返回一个惟一标识符,即 0xa9d57ac0f5046512 。 之后调用应用程序的函数时,须要记住/ 保存这个标识符。
以上部分是技术分析。接下来,让咱们看看如何经过 HTTP 调用一个应用的函数。
调用应用程序的函数不止局限于用户。 这篇文章解释了如何经过 Curl 等调用 Wasm 函数,你能够更好地理解请求和响应细节。
事实上,大多数时候,这些函数都是由机器编程调用的。至少,它们将经过网页浏览器或手机应用程序构建,并经过最终用户的“点击”来执行。
如今让咱们开始调用应用程序的函数。
将下面的 curl 命令复制并粘贴到终端中。也可使用相似于 Postman 这样的图形用户界面,来执行这个 HTTP 请求。
不要被下面的 --data
弄得晕头转向, 它其实是至关简单明了的。更多信息参见 HTTP POST 规范 。实际上,咱们只是调用函数 add_two_numbers
将两个数字相加并传入两个数字 [“2” ,“2”]
,指望返回值为 “4”
。
curl --header "Content-Type: application/json" \ --request POST \ --data '{"request": {"application": {"storage": "file_system", "uuid": "0xa9d57ac0f5046512"},"function": {"name": "add_two_numbers", "arguments": ["2", "2"],"argument_types": ["i32", "i32"], "return_types": ["i32"]},"modules": ["rust"] }}' \ http://13.54.168.1:8080/execute_wasm_function
{ "request": { "application": { "storage": "file_system", "uuid": "*0xa9d57ac0f5046512*" }, "function": { "name": "*add_two_numbers*", "arguments": ["*2*", "*2*"], "argument_types": ["i32", "i32"], "return_types": ["i32"] }, "modules": ["rust"] } }
上述两种方法都将生成结果对象,以下所示。返回值为 "return_value":["4"]
,结果是正确的。
{ "result": { "error_message": "", "gas": 0, "gas_used": 6, "return_value": [ "4" ], "status": "Succeeded", "vm_snapshot": { "global": [ [ 0, "0x0000000000100000" ], [ 1, "0x0000000000100000" ], [ 2, "0x0000000000100000" ] ] } }, "service_name": "0xa9d57ac0f5046512_1578786333_add_two_numbers", "uuid": "0xa9d57ac0f5046512" }
你可能会注意到,在返回数据中有一部分是 vm_snapshot
。 vm_snapshot
是什么呢?
虚拟机快照是由 Second State 的虚拟机(SSVM) 自己生成的数据。
最重要的是要记住 SSVM 自己是无状态的。 每次调用 SSVM 都会引发一个新的、干净的 SSVM 实例。
vm_snapshot
数据容许整体系统存储 SSVM 的最新已知状态。 经过存储这个 vm_snapshot
信息,咱们能够确保 SSVM 可以从上次没完成的地方继续。 使用这种方法,能够在下一次执行期间恢复 SSVM 的最后已知状态。
咱们在本文开头提到,终端用户并不须要了解系统的内部工做机制。 简单地说,若是最终用户重复调用一个函数,系统将表明它们处理全部的vm_snapshot
(VM 状态)。
本文 demo 了一个简单的有状态 Wasm 执行环境。在这个环境中,不管是终端用户或机器均可以使用每一个discrete Wasm 函数的逻辑进行交互。 仅经过网络就可使用 HTTP POST 请求。
这个演示只使用了简单的应用程序函数行 add_two_numbers
添加两个数字,但固然,您能够按照需求自由编写任何逻辑。
若是您对本文中的技术有任何疑问或须要任何帮助,请 GitHub与 Second State 联系。