当 Knative 遇见 WebAssembly
作者:易立
Knative 是在 Kubernetes 基礎(chǔ)之上的 Serverless 計算的技術(shù)框架,可以極大簡化 Kubernetes 應(yīng)用的開發(fā)與運維體驗。在 2022 年 3 月成為 CNCF 孵化項目。Knative 由兩個主要部分組成:一個是支持 HTTP 在線應(yīng)用的 Knative Serving,一個是支持 CloudEvents 和事件驅(qū)動應(yīng)用的 Knative Eventing。
Knative 可以支持各種容器化的運行時環(huán)境,我們今天來探索一下利用 WebAssembly 技術(shù)作為一個新的 Serverless 運行時。
從 WASM、WASI 到 WAGI
WebAssembly(簡稱 WASM)是一個新興的 W3C 規(guī)范。它是一個虛擬指令集體系架構(gòu)(virtual ISA),其初始目標(biāo)是為 C/C++等語言編寫的程序,可以安全和高效地運行在瀏覽器中。在 2019 年 12 月,W3C 正式宣布 WebAssembly 的核心規(guī)范成為Web標(biāo)準(zhǔn), 大大推進了 WASM 技術(shù)普及。今天,WebAssembly 已經(jīng)得到了 Google Chrome、Microsoft Edge、Apple Safari、Mozilla Firefox 等流瀏覽器的全面支持。而更加重要的是,WebAssembly 作為一個安全的、可移植、高效率的虛擬機沙箱,可以在任何地方、任何操作系統(tǒng),任何 CPU 體系架構(gòu)中安全地運行應(yīng)用。
Mozilla 在 2019 年提出了 WebAssembly System Interface(WASI),它提供類似 POSIX 這樣的標(biāo)準(zhǔn) API 來標(biāo)準(zhǔn)化 WebAssembly 應(yīng)用與文件系統(tǒng),內(nèi)存管理等系統(tǒng)資源的交互。WASI 的出現(xiàn)大大拓展了 WASM 的應(yīng)用場景,可以讓其作為一個虛擬機運行各種類型的服務(wù)端應(yīng)用。為了進一步推動 WebAssembly 生態(tài)發(fā)展,Mozilla、Fastly、英特爾和紅帽公司攜手成立了字節(jié)碼聯(lián)盟(Bytecode Alliance),共同領(lǐng)導(dǎo) WASI 標(biāo)準(zhǔn)、WebAssembly 運行時、工具等工作。后續(xù)微軟,谷歌、ARM 等公司也成為其成員。
WebAssembly 技術(shù)仍然在持續(xù)快速演進中,2022 年 4 月,W3C 公布了 WebAssembly 2.0 的第一批公共工作草案,這也成為其成熟與發(fā)展的重要標(biāo)志。
WASM/WASI 作為一種新興的后端技術(shù),具備的的原生安全、可移植、高性能,輕量化的特點,非常適于作為分布式應(yīng)用運行環(huán)境。與容器是一個一個獨立隔離的操作系統(tǒng)進程不同,WASM 應(yīng)用可以在一個進程內(nèi)部實現(xiàn)安全隔離,支持毫秒級冷啟動時間和極低的資源消耗。如下圖所示:
圖片來源:cloudflare
目前 WASM/WASI 還在發(fā)展初期,還有很多技術(shù)限制,比如不支持線程,無法支持低級 Socket 網(wǎng)絡(luò)應(yīng)用等等,這極大限制了 WASM 在服務(wù)器端的應(yīng)用場景。社區(qū)都在探索一個能夠充分適配 WASM 的應(yīng)用開發(fā)模型,揚長避短。微軟 Deislabs 的工程師從 HTTP 服務(wù)器發(fā)展的歷史中汲取靈感,提出了 WAGI - WebAssembly Gateway Interface 項目 [ 1] 。沒錯 WAGI 的概念就是來自于互聯(lián)網(wǎng)的上古傳奇,CGI。
CGI 是“公共網(wǎng)關(guān)接口”(Common Gateway Interface)的簡稱,是 HTTP 服務(wù)器與其它程序進行交互的一種規(guī)范。HTTP Server 通過標(biāo)準(zhǔn)輸入、輸出接口等與 CGI 腳本語言進行通信,開發(fā)者可以使用 Python/PHP/Perl 等各種實現(xiàn)來處理 HTTP 請求。
一個非常自然的推演,如果我們可以通過 CGI 規(guī)范來調(diào)用 WASI 應(yīng)用,開發(fā)者就可以非常輕松地利用 WebAssembly 來編寫 Web API 或者微服務(wù)應(yīng)用了,而且無需在 WASM 中處理太多的網(wǎng)絡(luò)實現(xiàn)細(xì)節(jié)。下圖就是 CGI 與 WAGI 的概念架構(gòu)圖對比:
二者架構(gòu)上高度相似,其不同之處是:傳統(tǒng) CGI 架構(gòu),每次 HTTP 請求會創(chuàng)建一個 OS 進程來進行處理,由操作系統(tǒng)的進程機制來實現(xiàn)安全隔離;而 WAGI 中 ,每次 HTTP 請求會在一個獨立的線程來中調(diào)用 WASI 應(yīng)用,應(yīng)用之間利用 WebAssembly 虛擬機實現(xiàn)安全隔離。在理論上,WAGI 可以有比 CGI 更低的資源損耗和更快的響應(yīng)時間。
本文不會對 WAGI 自身架構(gòu)以及 WAGI 應(yīng)用開發(fā)進行分析。有興趣的小伙伴可以自行閱讀項目文檔。
進一步思考,如果我們可以將 WAGI 作為一個 Knative Serving 運行時,我們就可以建立起一座將 WebAssembly 應(yīng)用于 Serverless 場景的橋梁。
WAGI 應(yīng)用冷啟動分析與優(yōu)化
冷啟動性能是 Serverless 場景的關(guān)鍵指標(biāo)。為了更好了了解 WAGI 執(zhí)行效率,我們可以利用 ab 做一個簡單的壓測:
$ ab -k -n 10000 -c 100 http://127.0.0.1:3000/...Server Software: Server Hostname: 127.0.0.1 Server Port: 3000Document Path: / Document Length: 12 bytesConcurrency Level: 100 Time taken for tests: 7.632 seconds Complete requests: 10000 Failed requests: 0 Keep-Alive requests: 10000 Total transferred: 1510000 bytes HTML transferred: 120000 bytes Requests per second: 1310.31 [#/sec] (mean) Time per request: 76.318 [ms] (mean) Time per request: 0.763 [ms] (mean, across all concurrent requests) Transfer rate: 193.22 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median max Connect: 0 0 0.6 0 9 Processing: 8 76 29.6 74 214 Waiting: 1 76 29.6 74 214 Total: 8 76 29.5 74 214Percentage of the requests served within a certain time (ms)50% 7466% 8875% 9580% 10090% 11595% 12598% 13999% 150100% 214 (longest request)我們可以看到 P90 請求響應(yīng)時間在 115ms,就這?這個和我們對 WASM 應(yīng)用輕量化的認(rèn)知不同。利用火焰圖,我們可以快速定位到問題所在:prepare_wasm_instance 函數(shù)消耗了整體應(yīng)用運行 80% 的時間。
經(jīng)過對代碼的分析,我們發(fā)現(xiàn)在每次響應(yīng) HTTP 請求過程中,WAGI 都要對已經(jīng)編譯過的 WSM 應(yīng)用,重新連接 WASI 以及 wasi-http 等擴展和并進行環(huán)境配置。這消耗了大量的時間。定位了問題,解決思路就非常簡單了,重構(gòu)執(zhí)行邏輯,讓這些準(zhǔn)備工作只在初始化過程中執(zhí)行一次,無需在每次 HTTP 請求過程中重復(fù)執(zhí)行。具體可參考優(yōu)化過的實現(xiàn) [ 2]
我們重新運行一遍壓力測試:
$ ab -k -n 10000 -c 100 http://127.0.0.1:3000/...Server Software: Server Hostname: 127.0.0.1 Server Port: 3000Document Path: / Document Length: 12 bytesConcurrency Level: 100 Time taken for tests: 1.328 seconds Complete requests: 10000 Failed requests: 0 Keep-Alive requests: 10000 Total transferred: 1510000 bytes HTML transferred: 120000 bytes Requests per second: 7532.13 [#/sec] (mean) Time per request: 13.276 [ms] (mean) Time per request: 0.133 [ms] (mean, across all concurrent requests) Transfer rate: 1110.70 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median max Connect: 0 0 0.6 0 9 Processing: 1 13 5.7 13 37 Waiting: 1 13 5.7 13 37 Total: 1 13 5.6 13 37Percentage of the requests served within a certain time (ms)50% 1366% 1575% 1780% 1890% 2195% 2398% 2599% 27100% 37 (longest request)在經(jīng)過優(yōu)化過的實現(xiàn)中,P90響應(yīng)時間已經(jīng)下降到 21ms,其中 prepare_wasm_instance 所占運行時間已經(jīng)下降到 17%。整體冷啟動效率有了很大的提升!
注:本文利用 flamegraph [ 3] 進行的性能分析。
利用 Knative 運行 WAGI 應(yīng)用
為了讓 WAGI 可以作為 Knative 應(yīng)用運行,我們還需在 WAGI 上增加了對 SIGTERM 信號的支持,讓 WAGI 容器支持優(yōu)雅下線。具體細(xì)節(jié)不再贅述。
Knative 的環(huán)境準(zhǔn)備可以參考 Knative 安裝文檔 [ 4] ,利用 Minikube 創(chuàng)建本地測試環(huán)境。
注:前提是需要有一定的網(wǎng)絡(luò)能力,因國內(nèi)無法訪問在 gcr.io 中的 Knative 鏡像。
一個更加簡單的方式是直接使用阿里云 Serverless 容器服務(wù) ASK [ 5] 上 Serverless K8s 集群。ASK 內(nèi)建了 Knative 支持 [ 6 ] ,無需復(fù)雜的配置安裝過程即可以開發(fā)和使用 Knative 應(yīng)用。
首先我們利用 WAGI 來定義一個 Knative 服務(wù):
apiVersion: serving.knative.dev/v1 kind: Service metadata:name: autoscale-waginamespace: default spec:template:metadata:annotations:# Knative concurrency-based autoscaling (default).autoscaling.knative.dev/class: kpa.autoscaling.knative.devautoscaling.knative.dev/metric: concurrency# Target 10 requests in-flight per pod.autoscaling.knative.dev/target: "10"# Disable scale to zero with a min scale of 1.autoscaling.knative.dev/min-scale: "1"# Limit scaling to 100 pods.autoscaling.knative.dev/max-scale: "10"spec:containers:- image: registry.cn-hangzhou.aliyuncs.com/denverdino/knative-wagi:0.8.1-with-cache其中:
-
容器鏡像 knative-wagi 包含了 WAGI 網(wǎng)關(guān)和一些示例的 WASI 應(yīng)用,更多細(xì)節(jié)可以參考項目 [ 7] 。
-
autoscale-wagi 服務(wù)可以根據(jù)請求數(shù)進行彈性伸縮
大家也可以進行一些壓測,學(xué)習(xí)一下 Knative 的彈性伸縮能力。
后記
本文介紹了 WAGI 這個項目,它可以將 HTTP 服務(wù)器的網(wǎng)絡(luò)處理細(xì)節(jié),與 WASM 應(yīng)用邏輯實現(xiàn)解耦。這樣可以輕松將 WASM/WASI 應(yīng)用與 Knative 這樣的 Serverless 框架相結(jié)合。一方面我們可以復(fù)用 Knative/K8s 帶來的彈性和大規(guī)模資源調(diào)度能力,一方面我們可以發(fā)揮 WebAssembly 帶來的安全隔離、可移植、輕量化等優(yōu)勢。
一脈相承的思考,在之前一篇文章《WebAssembly + Dapr = 下一代云原生運行時?》 中,我介紹了一個思路是將 WASM 應(yīng)用與外部服務(wù)依賴通過 Dapr 實現(xiàn)解耦,來解決可移植性與多樣化的服務(wù)能力之間的矛盾。
當(dāng)然這些工作還是簡單的玩具,只是用來驗證技術(shù)的可能性邊界。主要目的還是拋磚引玉,聽到大家關(guān)于下一代分布式應(yīng)用框架和運行時環(huán)境的思考和設(shè)想。
文章書寫過程中,忽然回憶起在 90 年代與師兄們一起根據(jù) RFC 規(guī)范來實現(xiàn) HTTP Server 與 CGI Gateway 的歲月,那是一種非常簡單而單純的快樂。在這里,也祝每一位技術(shù)人永葆好奇,享受每一天的編程時光。
點擊此處,了解阿里云 Serverless 容器服務(wù) ASK 更多詳情!
參考鏈接
[1] WAGI - WebAssembly Gateway Interface 項目:
https://github.com/deislabs/wagi
[2] 優(yōu)化過的實現(xiàn):
https://github.com/denverdino/wagi/tree/with_cache
[3] flamegraph:
https://github.com/flamegraph-rs/flamegraph
[4] Knative 安裝文檔:
https://knative.dev/docs/install/
[5] 阿里云 Serverless 容器服務(wù) ASK:
https://www.aliyun.com/product/cs/ask
[6] Knative 支持:
https://help.aliyun.com/document_detail/121508.html
[7] 項目:
https://github.com/denverdino/knative-wagi
總結(jié)
以上是生活随笔為你收集整理的当 Knative 遇见 WebAssembly的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ERC20协议API接口规范
- 下一篇: 北上或者南下之被摆了一道