Shopify如何在瀏覽器之外使用WebAssemblyShopify如何在瀏覽器外使用WebAssemblyShopify致力于讓大多數(shù)商家需要的功能變得簡單易用,通過接口在Shopify平臺上進行查詢、擴展和更改,從而為商家提供更多的可能性。有了這些接口,我們豐富的合作伙伴生態(tài)系統(tǒng)可以解決許多問題。這個生態(tài)系統(tǒng)主要......
Shopify致力于讓大多數(shù)商家需要的功能變得簡單易用,通過接口在Shopify平臺上進行查詢、擴展和更改,從而為商家提供更多的可能性。有了這些接口,我們豐富的合作伙伴生態(tài)系統(tǒng)可以解決許多問題。這個生態(tài)系統(tǒng)主要由“App”(獨立托管的Web服務(wù))來運營。該應(yīng)用程序通過網(wǎng)絡(luò)與Shopify進行通信。這種模式雖然功能強大,但是會帶來一系列的技術(shù)問題。我們的合作伙伴需要建立可以隨著Shopify的規(guī)模而擴展的Web服務(wù),這使得一些資源有限的合作伙伴更加捉襟見肘。即使合作伙伴擁有無限的資源,但與Shopify的通信所帶來的網(wǎng)絡(luò)延遲,也足以讓我們的App在要求高時效性的用例中失敗。
我們希望我們的合作伙伴可以專注于使用他們的專業(yè)知識來解決問題,而不是花費時間來管理可伸縮的Web服務(wù)。為了實現(xiàn)這個目標(biāo),我們保持了不受信任的伙伴代碼的靈活性,并在我們的基礎(chǔ)設(shè)施上運行它。為了保證這些代碼的性能、安全性和靈活性,我們選擇了WebAssembly作為通用格式。
web程序集
什么是WebAssemblyWebAssembly.org給出了如下定義:
WebAssembly (Wasm)是一種基于棧虛擬機的二進制指令格式。Wasm是一個為編程語言設(shè)計的可移植編譯目標(biāo),它使客戶機和服務(wù)器應(yīng)用程序能夠部署在Web上。"
要了解更多關(guān)于WebAssembly及其歷史的信息,您可以瀏覽這篇由Mozilla的Lin Clark撰寫的圖文并茂的文章。本文在此不再贅述。
Wasm通常與JavaScript一起運行在瀏覽器中,但Shopify采取了不同的方式,在瀏覽器外運行Wasm,不使用JavaScript。作為一種高性能語言,Wasm絕不是JavaScript的簡單替代品:它是為Web和非Web嵌入而設(shè)計的,解決了瀏覽器和代碼執(zhí)行引擎中廣泛存在的一個難題,即如何在不可信環(huán)境中高效執(zhí)行程序。Wasm滿足我們的三個主要技術(shù)要求:安全性、性能和靈活性。
安全
運行不受信任的代碼非常危險。本質(zhì)上,這些代碼不僅難以預(yù)測,而且很可能對整個Shopify平臺造成損害。雖然市面上沒有100%安全可靠的應(yīng)用程序,但我們?nèi)匀灰婪栋踩┒?,并在問題發(fā)生后采取措施減輕其影響。
Wasm將代碼執(zhí)行放在基于堆棧的沙盒環(huán)境中,依靠顯式導(dǎo)入與主機通信。因此,我們不能在Wasm中編寫任何惡意代碼。我們只能使用提供的輸入端口來操作虛擬環(huán)境。Wasm在這方面不同于字節(jié)碼,因為字節(jié)碼直接引用它們想要運行的計算機或操作系統(tǒng)。
Wasm還有許多不同的功能來保護用戶免受錯誤代碼的影響,包括受保護的調(diào)用堆棧和運行時類型檢查。關(guān)于Wasm安全模型的更多細節(jié)在WebAssembly.org上提供。
表演
在電子商務(wù)領(lǐng)域,更快的運行速度是商家推動業(yè)績增長的必要武器。如果Shopify提供的功能不能平衡加載時間和定制價值,那么這個功能就根本沒有價值。
Wasm自己的設(shè)計充分利用了常見的硬件功能,在各種平臺上發(fā)揮最接近的原生性能。面向追求最高性能,優(yōu)化瀏覽器執(zhí)行的開發(fā)者群體。因此,無論是現(xiàn)在還是未來,Wasm及其外圍工具在設(shè)計上都將側(cè)重于性能優(yōu)化。
靈活性
能夠幫助開發(fā)者提高開發(fā)效率的代碼執(zhí)行服務(wù)才是真正有用的服務(wù)。Wasm作為一種字節(jié)碼格式,兼容各種編譯器,為代碼開發(fā)者提供支持多種編程語言的一流開發(fā)體驗。這也使我們能夠在不改變底層執(zhí)行模型的情況下提供多語言支持。
基于社區(qū)
Shopyify基本保持了相同的開發(fā)目標(biāo)和設(shè)計,這為我們選擇Wasm提供了一個技術(shù)上的理由,但事實并不僅限于此:我們選擇Wasm不僅關(guān)乎技術(shù),更關(guān)乎人。如果Wasm生態(tài)系統(tǒng)被忽視了,或者只是奄奄一息,那么我們不會選擇它。集結(jié)號社區(qū)充滿活力和創(chuàng)新,潛力無窮。自從加入這個熱情的社區(qū)后,Shopify受益匪淺。
同樣,我們也在為社區(qū)貢獻自己的力量。通過收集用戶反饋,探索功能缺陷,并為我們使用的開源工具提交代碼貢獻。我們相信這為與WebAssembly社區(qū)建立良好的互利合作關(guān)系奠定了堅實的基礎(chǔ)基礎(chǔ),我們也期待在未來繼續(xù)為這個充滿活力的社區(qū)貢獻我們的力量。
代碼執(zhí)行服務(wù)的架構(gòu)
在簡單介紹了WebAssembly以及我們選擇它的原因之后,接下來就是深入探討我們的運行方案了。
我們使用Lucet,一個最初由Fastly開發(fā)的開源工具。Fastly,一家公司,為大量短命的、不可信的模塊提供了可編程的邊緣云平臺,使得它們可以在盡可能接近其發(fā)起地的地方執(zhí)行請求。這和我們的合作伙伴提供的代碼是一個問題,所以我們很自然的選擇了Lucet。
朗訊
Lucet是Wasm的運行時和編譯器。Wasm中的模塊保證了系統(tǒng)的安全性。因為我們不能在Wasm中編寫惡意代碼,所以Lucet利用Wasm模塊的驗證來檢查安全性。驗證后,模塊會被編譯成可執(zhí)行文件,性能可以達到原生狀態(tài)。此外,Wasm還支持預(yù)編譯,可以避免運行時編譯帶來的延遲。Lucet container在啟動時不需要做任何事情,這使得它的啟動時間達到了驚人的35μs。如果你對Lucet及其工作原理感興趣,可以查看Fastly的CTO泰勒·麥克馬倫的視頻。
Shopify Wasm發(fā)動機工作原理流程圖
我們將Lucet包裝在一個管理I/O和模塊存儲的Rust Web服務(wù)中,并稱之為Wasm engine。運行時,Shopify通過Web請求調(diào)用Wasm引擎來處理一些功能。之后,引擎在站點的上下文中調(diào)用應(yīng)用程序輸出,其中上下文可能涉及創(chuàng)建折扣、執(zhí)行約束或同步任何商家希望在平臺中進行個性化定制的服務(wù)。
行駛性能
下圖顯示了從我們最新的性能測試中提取的一些指標(biāo)。我們選擇了一個小函數(shù)和逆行測試:讓模塊限制添加到購物車的商品數(shù)量。測試過程中,每分鐘執(zhí)行10萬個模塊,時長約5分鐘。
模塊執(zhí)行所需的時間
此圖表顯示了執(zhí)行模塊所需時間的詳細信息,包括容器的I/O和模塊的執(zhí)行。y軸代表時間(單位:ms),x軸代表測試運行的具體時間。
圖中淺紫色的圖例表示在Lucet中執(zhí)行模塊所需的時間,其寬度徘徊在100μs左右,其余圖標(biāo)是I/O處理和引擎的細節(jié)??梢钥闯觯倛?zhí)行時間約為4 ms。所有時間顯示都是第99個百分比(99p)。為了更好的理解圖中時間的含義,我們來對比一下Shopify中優(yōu)秀的在線商店渲染服務(wù)Storefront Renderer的測試請求時間。
店面渲染器響應(yīng)時間
此圖表顯示了一段時間內(nèi)店面呈現(xiàn)器的請求時間。y軸表示請求時間(單位:秒),x軸表示返回值的具體時間。淺藍色線代表大約700毫秒的第99個百分比。
如果粗略估計模塊處理時間在5毫秒以內(nèi),可以說Lucet執(zhí)行時間的性能影響幾乎可以忽略不計。
生成WebAssembly
為了讓我們優(yōu)秀的執(zhí)行引擎發(fā)揮作用,我們還需要授權(quán)開發(fā)者創(chuàng)建兼容的Wasm模塊。Wasm的作用不是讓用戶自己寫代碼(如果他們愿意,當(dāng)然可以寫),而是作為編譯目標(biāo)存在。這讓我們思考以下問題:我們支持哪些編程語言,支持到什么程度。
理論上,Wasm支持的任何開發(fā)語言都是可能的。然而,我們更希望開發(fā)者能夠?qū)W⒂跒槠髽I(yè)解決問題,而不是研究如何符合我們的API。這就是為什么我們選擇單一語言Ruby支持,并為開發(fā)人員提供快速入門工具。但是,由于Ruby動態(tài)語言的特性,我們不能直接將其編譯成Wasm,涉及編譯解釋器的解決方案會有嚴(yán)重的性能損失。正因為如此,我們最終決定采用靜態(tài)編譯的語言,并把動態(tài)語言編譯的可能性留給了未來。
通過我們的研究發(fā)現(xiàn),Shopify生態(tài)系統(tǒng)中的大多數(shù)開發(fā)者都能熟練應(yīng)用JavaScript。不幸的是,JavaScript和Ruby一樣,是一種動態(tài)語言,所以不得不排除。最后,我們選擇了一種語法類似于TypeScript的開發(fā)語言:AssemblyScript。
使用匯編腳本
盡管WebAssembly支持大量的開發(fā)語言,但有兩種主要類型的編譯器我們不能使用:
生成環(huán)境或開發(fā)語言的特定產(chǎn)品的編譯器,即節(jié)點或瀏覽器。(例如Asterius、Blazor)
僅適用于特定運行時的編譯器。這些編譯器生成的模塊依賴于特定語言的特定導(dǎo)入,通常是為了支持某些特定語言的標(biāo)準(zhǔn)庫而存在的,這樣它們就可以在系統(tǒng)調(diào)用或運行時擁有可用的函數(shù)。因為我們不想被鎖定在某個特定的語言中,所以這種編譯器不在我們的考慮范圍之內(nèi)。(例如流明)
這些強大的編譯器在其他情況下可能會創(chuàng)造奇跡,但不幸的是它們不能被我們使用。我們需要可以生成WebAssembly的工具,而不是WebAssembly支持的工具。腳本是我們選擇的工具。
與WebAssembly中的其他工具一樣,AssemblyScript仍在開發(fā)中。它缺少一些關(guān)鍵功能,比如閉包支持,在邊緣情況下仍然會報告錯誤。這時,社區(qū)的重要性就顯現(xiàn)出來了。
開發(fā)語言AssemblyScript及其外圍工具擁有活躍用戶的愛好者和維護者社區(qū),他們自2019年Shopify首次使用AssemblyScript以來一直支持我們。而且我們還通過OpenCollective長期貢獻代碼支持社區(qū)。我們已經(jīng)編寫了一個語言服務(wù)器,在實現(xiàn)閉包方面取得了一些進展,并為編譯器和外圍工具提供了錯誤修復(fù)。
我們還將AssemblyScript整合到我們的早期工具中。在Shopify CLI中,我們允許開發(fā)人員通過命令行集成AssemblyScript來創(chuàng)建、測試和部署模塊。為了提高開發(fā)效率,我們提供了一個SDK,可以處理Shopify定義對象(比如“錢”)的底層實現(xiàn)。除了這些工具之外,我們還建立了一個允許合作伙伴監(jiān)控模塊的系統(tǒng),以便他們可以在模塊出現(xiàn)故障時收到警報。我們的最終目標(biāo)是讓合作伙伴能夠?qū)⑺麄兊拇a遷移到我們的平臺上,而不會失去代碼在原始平臺上的靈活性和可觀察性。
特別聲明:以上文章內(nèi)容僅代表作者本人觀點,不代表ESG跨境電商觀點或立場。如有關(guān)于作品內(nèi)容、版權(quán)或其它問題請于作品發(fā)表后的30日內(nèi)與ESG跨境電商聯(lián)系。
二維碼加載中...
使用微信掃一掃登錄
使用賬號密碼登錄
平臺顧問
微信掃一掃
馬上聯(lián)系在線顧問
小程序
ESG跨境小程序
手機入駐更便捷
返回頂部