WebAssembly + Dapr = 下一代云原生運(yùn)行時(shí)?
云計(jì)算已經(jīng)成為了支撐數(shù)字經(jīng)濟(jì)發(fā)展的關(guān)鍵基礎(chǔ)設(shè)施。云計(jì)算基礎(chǔ)設(shè)施也在持續(xù)進(jìn)化,從 IaaS,到容器即服務(wù)(CaaS),再到 Serverless 容器和函數(shù) PaaS (fPaaS 或者 FaaS),新的計(jì)算形態(tài)相繼出現(xiàn)。以容器和 Serverless 為代表的云原生技術(shù)正在重塑整個(gè)應(yīng)用生命周期。
在 Gartner 分析報(bào)告中,云計(jì)算基礎(chǔ)設(shè)施的發(fā)展路徑,也是云原生特質(zhì)逐漸增強(qiáng)的過(guò)程。其具體表現(xiàn)在:
模塊化越來(lái)越高- 更加細(xì)粒度的計(jì)算單元,如容器和 Serverless 函數(shù),更加適于微服務(wù)架構(gòu)的應(yīng)用交付,可以更加充分利用云的能力,提升架構(gòu)敏捷性。可編程性越來(lái)越高- 可以通過(guò)聲明式 API 和策略進(jìn)行實(shí)現(xiàn)自動(dòng)化管理與運(yùn)維,可以通過(guò) Immutable Infrastructure (不可變基礎(chǔ)設(shè)施)進(jìn)一步提升分布式應(yīng)用運(yùn)維的確定性。彈性效率越來(lái)越高- VM 可以實(shí)現(xiàn)分鐘級(jí)擴(kuò)容;容器與 Serverless 容器可以實(shí)現(xiàn)秒級(jí)擴(kuò)容;借助調(diào)度優(yōu)化,函數(shù)可以做到毫秒級(jí)擴(kuò)容。韌性越來(lái)越高- Kubernetes 提供了強(qiáng)大自動(dòng)化編排能力,提升應(yīng)用系統(tǒng)自愈性。而 Serverless 進(jìn)一步將穩(wěn)定性、可伸縮性和安全等系統(tǒng)級(jí)別復(fù)雜性下沉到基礎(chǔ)設(shè)施,開(kāi)發(fā)者只需關(guān)注自身業(yè)務(wù)應(yīng)用邏輯,進(jìn)一步釋放了生產(chǎn)力,提升系統(tǒng)的可恢復(fù)能力。
分布式云則是云計(jì)算發(fā)展的另外一個(gè)重要趨勢(shì),公有云的服務(wù)可以拓展到不同的物理位置,讓計(jì)算進(jìn)一步貼近客戶。分布式云讓客戶享受云計(jì)算的便利的同時(shí),也可以滿足對(duì)計(jì)算實(shí)時(shí)性和安全合規(guī)的訴求。這也推動(dòng)了企業(yè)應(yīng)用架構(gòu)的變化 - 應(yīng)用要能夠在不同的環(huán)境進(jìn)行部署、遷移,以最優(yōu)化的方式提供服務(wù)。
進(jìn)一步隨著移動(dòng)互聯(lián)網(wǎng),AI 與 IoT 等新技術(shù)的涌現(xiàn),無(wú)處不在的計(jì)算已經(jīng)成為現(xiàn)實(shí)。與此同時(shí),這也在催生算力的多樣性,X86 架構(gòu)一統(tǒng)天下的時(shí)代已經(jīng)過(guò)去,ARM/RISC-V 等芯片新勢(shì)力不但稱雄移動(dòng)通信和嵌入式設(shè)備領(lǐng)域,也在向邊緣計(jì)算和數(shù)據(jù)中心市場(chǎng)發(fā)起進(jìn)攻。開(kāi)發(fā)者甚至需要讓應(yīng)用支持不同的 CPU 體系架構(gòu),比如我們可以將一個(gè)圖像識(shí)別應(yīng)用部署在邊緣或者 IoT 等不同環(huán)境、不同體系架構(gòu)的設(shè)備之上運(yùn)行。
在分布式云、邊緣計(jì)算、云端一體等新的云計(jì)算場(chǎng)景下,下一代云原生應(yīng)用運(yùn)行時(shí)將具備什么樣的特點(diǎn)?
下一代云原生應(yīng)用運(yùn)行時(shí)
1. 無(wú)處不在的計(jì)算催生下一代可移植、高性能、輕量化的安全沙箱
容器應(yīng)用采用自包含的打包方式 -- 容器鏡像,它包含了應(yīng)用代碼和依賴的系統(tǒng)組件,可以實(shí)現(xiàn)應(yīng)用與基礎(chǔ)設(shè)施解耦,讓應(yīng)用可以在公共云、專有云等不同的運(yùn)行環(huán)境以一致的方式進(jìn)行部署、運(yùn)維,簡(jiǎn)化了彈性和遷移。此外 Docker 鏡像規(guī)范支持多架構(gòu)(Multi-Arch)鏡像,可以簡(jiǎn)化不同 CPU 體系架構(gòu)(如 x86, ARM 等)的應(yīng)用鏡像的構(gòu)建與分發(fā)。
函數(shù)應(yīng)用只包含用于事件響應(yīng)的代碼包,這將應(yīng)用交付格式從原生二進(jìn)制文件提升到了高級(jí)語(yǔ)言層面。這也給應(yīng)用的可移植性帶來(lái)了更大的想象空間,理論上甚至可以屏蔽執(zhí)行環(huán)境 CPU 體系架構(gòu)的差異。比如對(duì)于不依賴本地代碼的 Python/NodeJS 等腳本或者 Java 應(yīng)用,無(wú)需修改就可以在 x86 或者 ARM 等不同 CPU 架構(gòu)上運(yùn)行。
然而理想很豐滿,現(xiàn)實(shí)很骨感,可移植性和廠商鎖定是函數(shù) PaaS 發(fā)展的攔路虎。
很多腳本代碼依然需要通過(guò)調(diào)用原生代碼來(lái)實(shí)現(xiàn)數(shù)據(jù)處理和調(diào)用中間件(如數(shù)據(jù)庫(kù)驅(qū)動(dòng)),但是編譯原生代碼需要構(gòu)建環(huán)境與目標(biāo)執(zhí)行環(huán)境一致才能保障兼容性。比如 AWS Lambda / 阿里云函數(shù)計(jì)算都要求二進(jìn)制原生代碼依賴指定的內(nèi)核和 libc 版本。因此,越來(lái)越多的函數(shù) PaaS 服務(wù)支持容器鏡像作為載體,來(lái)簡(jiǎn)化函數(shù)應(yīng)用打包和依賴管理。函數(shù)應(yīng)用通常依賴后端服務(wù)(BaaS, Backend as a Service)實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)與計(jì)算處理等能力,由于 BaaS 不存在任何標(biāo)準(zhǔn),這樣很難將在 AWS Lambda 上開(kāi)發(fā)的函數(shù)應(yīng)用移植到阿里云的函數(shù)計(jì)算服務(wù)。
在 Serverless 計(jì)算中,現(xiàn)有的主流技術(shù)是利用沙箱容器技術(shù),如 AWS Firecraker 或者阿里云沙箱容器,來(lái)實(shí)現(xiàn)強(qiáng)隔離的安全執(zhí)行環(huán)境,但是也帶來(lái)更大的資源消耗。雖然現(xiàn)在阿里云沙箱容器經(jīng)過(guò)優(yōu)化可以實(shí)現(xiàn) 300ms 的冷啟動(dòng)速度,接近 Docker 這樣的 OS 容器啟動(dòng)速度,但是還無(wú)法滿足函數(shù) PaaS 毫秒級(jí)的啟動(dòng)要求,目前需要通過(guò)的調(diào)度策略,預(yù)留一定的 standby 實(shí)例才可以滿足,但是這樣也引入了更多的資源消耗。
WebAssembly(WASM) 是一個(gè)新的 W3C 規(guī)范,是一個(gè)通用、開(kāi)放、高效、安全的底層虛擬機(jī)抽象。它的設(shè)計(jì)初衷是為了解決JavaScript的性能問(wèn)題,使得 Web 應(yīng)用有接近本機(jī)原生應(yīng)用的性能。可以將現(xiàn)有編程語(yǔ)言應(yīng)用,如 C/C++, Rust 等,編譯成為 WASM 的字節(jié)碼,運(yùn)行在瀏覽器中的一個(gè)沙箱環(huán)境中。
WASM 讓應(yīng)用開(kāi)發(fā)技術(shù)與運(yùn)行時(shí)環(huán)境解耦,極大促進(jìn)了代碼復(fù)用。Mozilla 更在 2019 年推出了 WebAssembly System Interface(WASI),它提供類似 POSIX 這樣的標(biāo)準(zhǔn) API 來(lái)標(biāo)準(zhǔn)化 WebAssembly 與系統(tǒng)資源的交互抽象,比如文件系統(tǒng)訪問(wèn),內(nèi)存管理等。WASI 的出現(xiàn)拓展了 WASM 的應(yīng)用場(chǎng)景,可以讓其作為一個(gè)虛擬機(jī)運(yùn)行各種類型的服務(wù)端應(yīng)用。WASM/WASI 為應(yīng)用的可移植性帶來(lái)全新的希望,為了進(jìn)一步推動(dòng) WebAssembly 生態(tài)發(fā)展,Mozilla、Fastly、英特爾和紅帽公司攜手成立了字節(jié)碼聯(lián)盟(Bytecode Alliance),共同領(lǐng)導(dǎo) WASI 標(biāo)準(zhǔn)、 WebAssembly 運(yùn)行時(shí)、工具等工作。
WebAssembly 所具備的的安全、可移植、高效率,輕量化的特點(diǎn),為應(yīng)用沙箱的發(fā)展帶來(lái)了全新的思路。WASM 可以輕松實(shí)現(xiàn)毫秒級(jí)冷啟動(dòng)時(shí)間和極低的資源消耗。同時(shí) WASM 字節(jié)碼比原生機(jī)器碼有更高的安全級(jí)別。此外,WASI 實(shí)現(xiàn)了細(xì)粒度基于能力的安全模型,遵循最小權(quán)限原則。在執(zhí)行過(guò)程中,WASI 應(yīng)用只能訪問(wèn)由依賴注入指明的確切資源集,這種方式與傳統(tǒng)粗粒度的操作系統(tǒng)級(jí)隔離相比,進(jìn)一步收斂了安全攻擊面。
正因如此,WASM/WASI 得到了 Serverless、IoT/邊緣計(jì)算等社區(qū)的廣泛關(guān)注。Fastly、Cloudflare 等廠商相繼發(fā)布了基于 WebAssembly 技術(shù)實(shí)現(xiàn)了更加輕量化的 Serverless 服務(wù)。
然而 WebAssembly 在服務(wù)器端的應(yīng)用之路依然布滿荊棘。首先 WASI 的能力還在非常早期的狀態(tài),一些關(guān)鍵能力依然缺失,首當(dāng)其沖的就是缺乏標(biāo)準(zhǔn)化的網(wǎng)絡(luò)訪問(wèn)能力:https://github.com/WebAssembly/WASI/issues/315。
目前 WASI 應(yīng)用僅能做一些計(jì)算類任務(wù),基本無(wú)法實(shí)現(xiàn)分布式應(yīng)用,也無(wú)法調(diào)用多樣性的后端服務(wù)和 Redis、MySQL、Kafka 等應(yīng)用中間件。這大大限制了 WASI 的應(yīng)用場(chǎng)景。
當(dāng)理想撞上現(xiàn)實(shí),頭破血流還是絕處逢生?
2. 下一代可移植應(yīng)用運(yùn)行時(shí)加速編程界面上移,應(yīng)用基礎(chǔ)設(shè)施能力下沉
Dapr 是微軟開(kāi)源的面向云原生應(yīng)用的分布式應(yīng)用運(yùn)行時(shí),目標(biāo)使所有開(kāi)發(fā)人員能夠使用任何語(yǔ)言和任何框架輕松地構(gòu)建彈性的、事件驅(qū)動(dòng)的、可移植的微服務(wù)應(yīng)用。
Dapr 實(shí)現(xiàn)了一系列構(gòu)建高性能、可伸縮、高可用的分布式應(yīng)用的設(shè)計(jì)模式,比如提供了服務(wù)發(fā)現(xiàn)和服務(wù)調(diào)用能力,也實(shí)現(xiàn)了一個(gè)簡(jiǎn)單、一致的編程模型來(lái)支持事件驅(qū)動(dòng)應(yīng)用架構(gòu)。
此外 Dapr 通過(guò)基礎(chǔ)設(shè)施屏蔽了應(yīng)用訪問(wèn)后端服務(wù)的技術(shù)細(xì)節(jié),如資源綁定、安全管理,可觀測(cè)性等等。這個(gè)對(duì) Serverless 應(yīng)用非常重要,一方面將開(kāi)發(fā)和部署進(jìn)行了解耦,讓開(kāi)發(fā)者和運(yùn)維團(tuán)隊(duì)可以通過(guò)關(guān)注點(diǎn)分離簡(jiǎn)化系統(tǒng)復(fù)雜性;一方面,可以將短生命周期、無(wú)狀態(tài)的 Serverless 應(yīng)用邏輯,與數(shù)據(jù)庫(kù)連接池管理這樣的長(zhǎng)期運(yùn)行,有狀態(tài)的中間件訪問(wèn)能力進(jìn)行解耦,提升了 Serverless 應(yīng)用的可伸縮性和運(yùn)行效率。
“Any language, any framework, anywhere” 是 Dapr 的重要設(shè)計(jì)目標(biāo)。Dapr 通過(guò)在應(yīng)用和后端服務(wù)之間,通過(guò) Sidecar 方式提供一個(gè)抽象層,并通過(guò)標(biāo)準(zhǔn)化的 HTTP/gRPC API 實(shí)現(xiàn)了應(yīng)用的可移植性,和后端服務(wù)的可替換性。
走向詩(shī)和遠(yuǎn)方
我們可以將 WebAssembly 和 Dapr 相結(jié)合,來(lái)實(shí)現(xiàn)可移植、強(qiáng)隔離、輕量化的微服務(wù)應(yīng)用架構(gòu)。Dapr sidecar 與 WASM 虛擬機(jī)部署在一起。WASI 應(yīng)用通過(guò) HTTP/gRPC 訪問(wèn)本地的 Dapr 服務(wù)端點(diǎn),由 Dapr 代理連接各種后端服務(wù)或者實(shí)現(xiàn)服務(wù)間通信。
這樣的架構(gòu)設(shè)計(jì)讓 WASI 應(yīng)用的安全邊界非常清晰,符合 WASI 安全模型,WASI 應(yīng)用只能通過(guò) Dapr sidecar 實(shí)現(xiàn)外部服務(wù)訪問(wèn)。同時(shí)在這個(gè)架構(gòu)中,只有 WASM 虛擬機(jī)和 Dapr 作為可信的環(huán)境依賴以原生機(jī)器碼運(yùn)行。而應(yīng)用是可移植的 WASM 字節(jié)碼,大大提升了架構(gòu)的可移植性和安全性。
來(lái)自微軟 Deis Labs 的 Radu Matei,最近提供了一個(gè)實(shí)驗(yàn)性項(xiàng)目可以為 WASI 添加 HTTP 支持。詳見(jiàn):https://deislabs.io/posts/wasi-experimental-http/ 。
在此基礎(chǔ)上,我們來(lái)構(gòu)建一個(gè)最小原型,驗(yàn)證 WebAssembly 與 Dapr 相結(jié)合的技術(shù)可行性。
1. Dapr 環(huán)境準(zhǔn)備
我們首先按照 https://docs.dapr.io/getting-started/ 的流程:
$ dapr init Making the jump to hyperspace... Downloading binaries and setting up components... Downloaded binaries and completed components set up. daprd binary has been installed to /Users/yili/.dapr/bin. dapr_placement container is running. dapr_redis container is running. dapr_zipkin container is running. Use `docker ps` to check running containers. Success! Dapr is up and running. To get started, go here: https://aka.ms/dapr-getting-started$ dapr run --app-id myapp --dapr-http-port 3500WARNING: no application command found. Starting Dapr with id myapp. HTTP Port: 3500. gRPC Port: 63734 Checking if Dapr sidecar is listening on HTTP port 3500... Checking if Dapr sidecar is listening on GRPC port 63734 Dapr sidecar is up and running. You're up and running! Dapr logs will appear here.
2. 利用 Redis 作為 WASI 應(yīng)用的狀態(tài)存儲(chǔ)
我們下面利用 Dapr 的 Get Started 的例子,利用 Redis 作為 WASI 應(yīng)用的狀態(tài)存儲(chǔ)。具體邏輯如下圖。
注:下面的應(yīng)用需要 Rust 和 AssemblyScript 環(huán)境配置,請(qǐng)大家自行完成。
我們?cè)?Radu 項(xiàng)目的基礎(chǔ)上 fork 了一個(gè)版本,首先來(lái)下載代碼,并進(jìn)行構(gòu)建。
$ git clone https://github.com/denverdino/wasi-experimental-http$ cd wasi-experimental-http$ cargo build... Finished dev [unoptimized + debuginfo] target(s) in 3m 02s
我們利用 AssemblyScript 來(lái)實(shí)現(xiàn)了這個(gè)測(cè)試應(yīng)用,測(cè)試代碼如下:
$ cat tests/dapr/index.ts// @ts-ignoreimport { Console } from "as-wasi";import { DaprClient, StateItem } from "./dapr";import { JSON } from "assemblyscript-json";Console.log("Testing Dapr API ....")let dapr = new DaprClient()dapr.saveState("statestore", "weapon", JSON.Value.String("Death Star"))let o = JSON.Value.Object()o.set("name", "Tatooine")o.set("test", 123)let item = new StateItem("planets", o)let items: StateItem[] = [item]dapr.saveBulkState("statestore", items)let testObj = dapr.getState("statestore", "planets")let testStr = dapr.getState("statestore", "weapon")if (testStr.toString() == "Death Star" && testObj.isObj && (<JSON.Integer>(<JSON.Obj>testObj).getInteger("test")).valueOf() == 123) { Console.log("Test successfully!")} else { Console.log("Test failed!")}
代碼邏輯非常簡(jiǎn)單,就是創(chuàng)建一個(gè) Dapr 客戶端,然后通過(guò) REST API,進(jìn)行 Dapr 的狀態(tài)管理。我們可以快速驗(yàn)證一下。
$ cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.19s Running `target/debug/wasi-experimental-http-wasmtime-sample`Testing Dapr API ....POST http://127.0.0.1:3500/v1.0/state/statestore with [{"key":"weapon","value":"Death Star"}]POST http://127.0.0.1:3500/v1.0/state/statestore with [{"key":"planets","value":{"name":"Tatooine","test":123}}]GET http://127.0.0.1:3500/v1.0/state/statestore/planetsGET http://127.0.0.1:3500/v1.0/state/statestore/weaponTest successfully!module instantiation time: 333.16637ms
3. 關(guān)鍵要點(diǎn)分析
wasi-experimental-http 項(xiàng)目在 Wasmtime (來(lái)自 Bytecode Alliance 的一個(gè) WASM 實(shí)現(xiàn))虛擬機(jī)上實(shí)現(xiàn)了擴(kuò)展,支持在 WASI 應(yīng)用中,訪問(wèn) HTTP 服務(wù)。它還提供了一個(gè) AssemblyScript 的 HTTP Client 實(shí)現(xiàn)。
wasi-experimental-http 項(xiàng)目:https://github.com/deislabs/wasi-experimental-http/。
在此之上,我們?yōu)?AssemblyScript 提供一個(gè) Dapr 的封裝,可以參見(jiàn):https://github.com/denverdino/wasi-experimental-http/blob/main/tests/dapr/dapr.ts。
// @ts-ignoreimport { Console } from "as-wasi";import { Method, RequestBuilder, Response } from "../../crates/as";import { JSONEncoder, JSON } from "assemblyscript-json";export class StateItem { key: string value: JSON.Value etag: string | null metadata: Map<string, string> | null constructor(key: string, value: JSON.Value) { this.key = key this.value = value this.etag = null this.metadata = null }}...export class DaprClient { port: i32 address: string constructor() { this.address = "127.0.0.1" this.port = 3500 } stateURL(storeName: string): string { return "http://" + this.address + ":" + this.port.toString() + "/v1.0/state/" + storeName } saveState(storeName: string, key: string, value: JSON.Value): boolean { let item = new StateItem(key, value) let items: StateItem[] = [item] return this.saveBulkState(storeName, items) } saveBulkState(storeName: string, items: StateItem[]): boolean { // Handle field let encoder = new JSONEncoder(); // Construct necessary object encoder.pushArray(null); for (let i = 0, len = items.length; i < len; i++) { let item = items[i] encoder.pushObject(null); encoder.setString("key", item.key) encodeValue(encoder, "value", item.value) if (item.etag != null) { encoder.setString("etag", <string>item.etag) } encoder.popObject() }; encoder.popArray(); // Or get serialized data as string let jsonString = encoder.toString(); let url = this.stateURL(storeName); Console.log("POST " + url + " with " + jsonString); let res = new RequestBuilder(url) .method(Method.POST) .header("Content-Type", "application/json") .body(String.UTF8.encode(jsonString)) .send(); let ok = res.status.toString() == "200" res.close(); return ok } getState(storeName: string, key: string): JSON.Value { let url = this.stateURL(storeName) + "/" + key; Console.log("GET " + url); let res = new RequestBuilder(url) .method(Method.GET) .send(); let ok = res.status.toString() == "200" let result = <JSON.Value> new JSON.Null() if (ok) { let body = res.bodyReadAll(); result = <JSON.Value>JSON.parse(body) } res.close(); return result }};
測(cè)試應(yīng)用的 main 函數(shù),會(huì)創(chuàng)建一個(gè) Wasmtime 運(yùn)行時(shí)環(huán)境,并為其添加為 HTTP 擴(kuò)展,并加載執(zhí)行測(cè)試應(yīng)用的 WASM 字節(jié)碼:https://github.com/denverdino/wasi-experimental-http/blob/main/src/main.rs。
fn main() { let allowed_domains = Some(vec![ "http://127.0.0.1:3500".to_string(), ]); let module = "tests/dapr/build/optimized.wasm"; create_instance(module.to_string(), allowed_domains.clone()).unwrap();}/// Create a Wasmtime::Instance from a compiled module and/// link the WASI imports.fn create_instance( filename: String, allowed_domains: Option<Vec<String>>,) -> Result<Instance, Error> { let start = Instant::now(); let store = Store::default(); let mut linker = Linker::new(&store); let ctx = WasiCtxBuilder::new() .inherit_stdin() .inherit_stdout() .inherit_stderr() .build()?; let wasi = Wasi::new(&store, ctx); wasi.add_to_linker(&mut linker)?; // Link `wasi_experimental_http` let http = HttpCtx::new(allowed_domains, None)?; http.add_to_linker(&mut linker)?; let module = wasmtime::Module::from_file(store.engine(), filename)?; let instance = linker.instantiate(&module)?; let duration = start.elapsed(); println!("module instantiation time: {:#?}", duration); Ok(instance)}
道阻且長(zhǎng),行則將至
WASM/WASI 為輕量化、可移植、缺省安全的應(yīng)用運(yùn)行時(shí)提供了良好的基礎(chǔ),在區(qū)塊鏈等領(lǐng)域 WebAssembly 已經(jīng)得到了廣泛的應(yīng)用。然而,對(duì)于通用性的服務(wù)器端應(yīng)用,WASM/WASI 的差距還非常明顯。由于 berkeley socket 這樣標(biāo)準(zhǔn)化的網(wǎng)絡(luò)編程接口的缺失,只能通過(guò)擴(kuò)展 WASM 虛擬機(jī)的方式來(lái)進(jìn)行補(bǔ)齊。此外 WASM 的多線程能力還沒(méi)有被標(biāo)準(zhǔn)化,目前的 HTTP 調(diào)用采用阻塞式同步調(diào)用,還無(wú)法實(shí)現(xiàn)高效和穩(wěn)定的網(wǎng)絡(luò)通信。
此外,另外 WASM/WASI 的一個(gè)短板就是開(kāi)發(fā)效率和生態(tài)建設(shè)。目前而言,雖然眾多的編程語(yǔ)言已經(jīng)逐漸開(kāi)始提供 WebAssembly 的支持,但是對(duì)于普通開(kāi)發(fā)者而言,AssemblyScript 這樣的腳本語(yǔ)言是更加合適的選擇。AssemblyScript 復(fù)用了 TypeScript 的語(yǔ)法,與 Rust/C++ 相比,大大降低了學(xué)習(xí)曲線,也提供了非常好的 IDE 工具體驗(yàn),如 VS Code 等。但是與 TypeScripty 通過(guò)翻譯成為 JavaScript 執(zhí)行不同,AssemblyScript 應(yīng)用會(huì)被編譯成 WASM 字節(jié)碼執(zhí)行。AssemblyScript 本質(zhì)上是一個(gè)靜態(tài)類型的編譯型語(yǔ)言,本質(zhì)上與 JS/TS 這樣的動(dòng)態(tài)類型的解釋型語(yǔ)言非常不同。二者在語(yǔ)法上也有一些不同,比如目前 AssemblyScript 缺少對(duì)閉包 (closure) 和正則表達(dá)式 (Regex) 等常用功能支持,這讓開(kāi)發(fā) WASM 應(yīng)用還是有一定的技術(shù)門檻。
另外與 NPM 強(qiáng)大的生態(tài)相比,AssemblyScript 社區(qū)也很年輕。很多功能都需要從頭構(gòu)建,比如對(duì) JSON 的序列化與反序列化,我們選擇了 _https://github.com/nearprotocol/assemblyscript-json_ ,但是其易用性和性能與成熟的 JSON 類庫(kù)還有一定差距。當(dāng)然我們也看到 AssemblyScript 的快速成長(zhǎng),以及越來(lái)越多的開(kāi)發(fā)者開(kāi)始貢獻(xiàn) AssemblyScript 代碼庫(kù),比如 regex 支持等等。
Dapr 的出現(xiàn)為 WASM/WASI 開(kāi)發(fā)通用的分布式應(yīng)用,尤其是為可移植的、Serverless 化的應(yīng)用帶來(lái)另外一縷曙光。然而 Dapr 也并非完美:API 標(biāo)準(zhǔn)化在提升對(duì)后端服務(wù)可移植性的同時(shí)也阻礙了對(duì)差異化能力的支持。Sidecar 架構(gòu)在提升靈活性的同時(shí)增加了部署和管理復(fù)雜性。
作為一個(gè)理性樂(lè)觀派,任何技術(shù)都有其青澀的時(shí)代,期待社區(qū)的共同努力讓計(jì)算無(wú)處不在、創(chuàng)新觸手可及的理想成為現(xiàn)實(shí)。