本文 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 聯繫。