掘力計劃22期-基于 WebAssembly 打造一個純?yōu)g覽器上的POSIX 運行環(huán)境
8月19日,在掘力計劃系列第22場《聊聊前端工程化實踐和未來》活動中,來自阿里的劉睿老師受邀進行了一場主題為《基于 WebAssembly 打造一個純?yōu)g覽器上的POSIX 運行環(huán)境》的技術(shù)分享。

劉睿老師是一位擁有8年互聯(lián)網(wǎng)工作經(jīng)驗的專業(yè)人士,他目前就職于阿里巴巴TRE工程基礎(chǔ)服務(wù)團隊,主要從事于中后臺、內(nèi)部工具產(chǎn)品的應(yīng)用層開發(fā),在領(lǐng)域內(nèi)有著豐富的實踐經(jīng)驗和深厚的技術(shù)功底。
這次劉老師結(jié)合自身在WebAssembly領(lǐng)域的研究與探索,通過介紹阿里內(nèi)部開發(fā)的WebIDE產(chǎn)品WebC與目前市面上類似產(chǎn)品講述了WebAssembly在構(gòu)建純前端POSIX運行環(huán)境方面的應(yīng)用沒,以及與之相關(guān)的技術(shù)和實現(xiàn)方式。
背景
在 2021 年 Google I/O 大會上,StackBlitz 正式推出了與 Next.js 以及 Google Chrome 團隊合作開發(fā)的一項基于 WebAssembly 的新技術(shù),名為?WebContainers?。
基于 WebContainers (以及開源的 VS Code Web),StackBlitz 構(gòu)建了全新的在線 IDE 產(chǎn)品?CodeFlow。

劉睿老師提到在阿里內(nèi)部也存在云端研發(fā)場景的用戶訴求存在,因此從去年開始就在著手打造類 “WebContainers” 相關(guān)的產(chǎn)品,面向云研發(fā)用戶提供高效運行 Node.js 、bash、git、 Core Utils等終端能力。
WebContainers 的優(yōu)勢相比于WebIDE無容器、WebIDE Docker的方案更加的輕量且無額外成本,功能相對完善。因此,伴隨著WebContainers技術(shù)的出現(xiàn),基于WebContainers的WebIDE體驗普遍獲得了明顯的體驗提升。
在下文中,我們將WebAssembly和WebContainers分別簡稱為WASM和WebC,以便更加簡潔和方便地提及它們。
WebC 實現(xiàn)方式
類比本地而言,WebC 更像是一個運行在瀏覽器上的操作系統(tǒng)。不同之處在于Wasm?跟?WebC?有兩層關(guān)系:
WebC?本身使用 Wasm 實現(xiàn)。
.wasm?是?WebC?中的可執(zhí)行文件格式,就好比?ELF?之于?*nix、PE?之于?Windows、Mach-O?之于?macOS。
如下圖所示:

數(shù)據(jù)傳遞
瀏覽器 Worker 間傳遞數(shù)據(jù)通常存在三種方式:
ArrayBuffer + MessageChannel (COPY)
ArrayBuffer + MessageChannel + transferable (MOVE)
SharedArrayBuffer + Atomics
雖然 ShardArrayBuffer 因為安全問題被瀏覽器默認關(guān)閉,但是ShardArrayBuffer +Atomics方案依然是目前比較好的數(shù)據(jù)傳遞方式選項。其原因主要是因為 WebC 大量核心邏輯(文件系統(tǒng)、進程管理、管道、TTY/PTY等)由 C++實現(xiàn),而在 Wasm 中調(diào)用諸如 PostMessage等 Web API需要JS 做大量膠水工作。

從 WebC 多進程深? Wasm
類?本地,WebC 更像是?個運?在瀏覽器上的操作系統(tǒng),WebC 本身也是使? Wasm 實現(xiàn)的。

WebC 共享內(nèi)存設(shè)計 & Wasm 類型
WebC在設(shè)計上選擇了SharedArrayBuffer+Atomics的方案進行不同進程間的數(shù)據(jù)傳遞。相比消息通道的傳遞方式,這種基于共享內(nèi)存的設(shè)計可以避免大量的數(shù)據(jù)拷貝開銷。Wasm中的SharedArrayBuffer和Atomics可在多線程/進程間高效安全地進行數(shù)據(jù)交換。這也更契合WebC的場景,大量核心邏輯由C++編寫,消息通道方式將帶來更多JS膠水層的額外性能損耗。

內(nèi)存隔離問題 & Wasm 內(nèi)存和變量
WebC需要在不同的進程間進行內(nèi)存隔離。Wasm中的內(nèi)存布局包括Global、Local和Linear Memory三個部分。其中Global區(qū)域可以用于實現(xiàn)數(shù)據(jù)的邏輯隔離。WebC就是通過控制Wasm的內(nèi)存布局,為每個進程預(yù)留獨立的Global內(nèi)存空間,從而實現(xiàn)了進程間內(nèi)存的隔離。這展示了Wasm內(nèi)存模型的靈活性和隔離特性在構(gòu)建安全的運行環(huán)境方面的應(yīng)用價值。


Fork 函數(shù) & Wasm Call 和 Stack-Switching
“fork”函數(shù)可以通過保存和恢復(fù)程序計數(shù)器來實現(xiàn)進程的創(chuàng)建。但是在Wasm中,函數(shù)的調(diào)用對開發(fā)者是不透明的。Wasm中的調(diào)用無法保存和恢復(fù)調(diào)用現(xiàn)場。這也導(dǎo)致了Wasm目前無法調(diào)用異步JS接口的問題。Stack-Switching提案將通過“棧切換”功能實現(xiàn)類似于fork的上下文切換效果。這為Wasm帶來了實現(xiàn)類似fork的能力。

WebC “系統(tǒng)調(diào)?”& Wasm Linking
WebC 并沒有真正的系統(tǒng)調(diào)?,但是依然存在程序訪問系統(tǒng)接?的過程。?前 Wasm Module 之間是?法直接 link 的,?如在前端,我們必須使? JS 作為膠?層。解決這個問題的 Wasm Module Linking Proposal 也被合? Component Model Proposal(階段1)。

Pipe & Wasm 編程
以下示例展示了Wasm提供底層內(nèi)存訪問和計算的優(yōu)勢,可進行更高效的位操作和內(nèi)存管理。



對 Wasm 未來的一點小期待
劉睿老師提到說現(xiàn)在的 Wasm 并沒有像期待的那樣給前端帶來革新,根據(jù)Results for js web frameworks benchmark得出的調(diào)研結(jié)果來看目前基于 Wasm 的前端框架性能普遍上不如 JS 框架。

或許是由于WASM本身功能的缺陷導(dǎo)致需要大量膠水層產(chǎn)生來修補才能夠很好的進行工作,當(dāng)?Component?Model,Stack-Switching,?GC?這些?proposals?落地之后,Wasm?在前端的應(yīng)用可以完全擺脫對?JS?的依賴以及膠水層產(chǎn)生的性能損失,基于?Wasm?的前端框架可以充分發(fā)揮自己的性能優(yōu)勢。
如下圖所示:

總結(jié)
WebC產(chǎn)品展示了Wasm構(gòu)建瀏覽器運行環(huán)境的可能性。但要發(fā)揮Wasm性能優(yōu)勢,仍需不斷迭代和優(yōu)化。本文對其實現(xiàn)原理和應(yīng)用場景進行了一定分析,希望對相關(guān)領(lǐng)域的探索提供一定借鑒和啟發(fā)。
參考資料
https://krausest.github.io/js-framework-benchmark/2023/table_chrome_116.0.5845.82.html
https://webcontainers.io/
關(guān)于掘力計劃
掘力計劃由稀土掘金技術(shù)社區(qū)發(fā)起,致力于打造一個高品質(zhì)的技術(shù)分享和交流的系列品牌。聚集國內(nèi)外頂尖的技術(shù)專家、開發(fā)者和實踐者,通過線下沙龍、閉門會、公開課等多種形式分享最前沿的技術(shù)動態(tài)。