超越瀏覽器:無服務器 WebAssembly 入門
已發表: 2022-03-10現在所有主要瀏覽器和全球 85% 以上的用戶都支持 WebAssembly,JavaScript 不再是唯一的瀏覽器語言。 如果你沒有聽說過,WebAssembly 是一種在瀏覽器中運行的新的低級語言。 它也是一個編譯目標,這意味著您可以將用 C、C++ 和 Rust 等語言編寫的現有程序編譯成 WebAssembly,並在瀏覽器中運行這些程序。 到目前為止,WebAssembly 已被用於將各種應用程序移植到 Web,包括桌面應用程序、命令行工具、遊戲和數據科學工具。
注意:有關如何在瀏覽器中使用 WebAssembly 來加速 Web 應用程序的深入案例研究,請查看我之前的文章。
WebAssembly 在 Web 之外?
儘管當今大多數 WebAssembly 應用程序都是以瀏覽器為中心的,但 WebAssembly 本身最初並不是為 Web 設計的,而是真正為任何沙盒環境設計的。 事實上,最近有很多興趣探索 WebAssembly 如何在瀏覽器之外發揮作用,作為在任何操作系統或計算機架構上運行二進製文件的通用方法,只要有支持該系統的 WebAssembly 運行時。 在本文中,我們將了解如何以無服務器/功能即服務 (FaaS) 方式在瀏覽器之外運行 WebAssembly。
用於無服務器應用程序的 WebAssembly
簡而言之,無服務器函數是一種計算模型,您將代碼交給雲提供商,讓他們為您執行和管理代碼擴展。 例如,您可以要求在您調用 API 端點時執行無服務器函數,或者由事件驅動,例如文件上傳到雲存儲桶時。 雖然術語“無服務器”可能看起來用詞不當,因為服務器顯然在此過程中涉及到某個地方,但從我們的角度來看,它是無服務器的,因為我們不需要擔心如何管理、部署或擴展這些服務器。
儘管這些函數通常是用 Python 和 JavaScript (Node.js) 等語言編寫的,但您可能選擇使用 WebAssembly 的原因有很多:
- 更快的初始化時間
支持 WebAssembly 的無服務器提供商(包括 Cloudflare 和 Fastly 報告說,他們啟動功能的速度至少比大多數雲提供商使用其他語言的速度快一個數量級。他們通過在同一進程中運行數万個 WebAssembly 模塊來實現這一點,即之所以可能,是因為 WebAssembly 的沙盒特性提供了一種更有效的方式來獲得容器傳統上使用的隔離。 - 無需重寫
WebAssembly 在瀏覽器中的主要吸引力之一是能夠將現有代碼移植到 Web,而無需將所有內容重寫為 JavaScript。 這種優勢在無服務器用例中仍然適用,因為雲提供商限制了您可以使用哪些語言編寫無服務器函數。通常,它們將支持 Python、Node.js 以及其他一些,但肯定不支持 C、C++ 或 Rust . 通過支持 WebAssembly,無服務器提供商可以間接支持更多的語言。 - 更輕量級
在瀏覽器中運行 WebAssembly 時,我們依賴最終用戶的計算機來執行我們的計算。 如果這些計算過於密集,我們的用戶會在他們的電腦風扇開始嗡嗡作響時不高興。 在瀏覽器之外運行 WebAssembly 為我們提供了 WebAssembly 的速度和可移植性優勢,同時還保持了我們的應用程序的輕量級。 最重要的是,由於我們在更可預測的環境中運行我們的 WebAssembly 代碼,我們可以潛在地執行更密集的計算。
一個具體的例子
在我之前在 Smashing Magazine 上的文章中,我們討論瞭如何通過將慢速 JavaScript 計算替換為編譯為 WebAssembly 的 C 代碼來加速 Web 應用程序。 有問題的網絡應用程序是 fastq.bio,這是一個預覽 DNA 測序數據質量的工具。
作為一個具體的例子,讓我們將 fastq.bio 重寫為一個使用無服務器 WebAssembly 的應用程序,而不是在瀏覽器中運行 WebAssembly。 在本文中,我們將使用 Cloudflare Workers,這是一個支持 WebAssembly 並構建在 V8 瀏覽器引擎之上的無服務器提供商。 另一家云提供商 Fastly 正在開發類似的產品,但基於他們的 Lucet 運行時。
首先,讓我們編寫一些 Rust 代碼來分析 DNA 測序數據的數據質量。 為方便起見,我們可以利用 Rust-Bio 生物信息學庫來處理輸入數據的解析,並利用 wasm-bindgen 庫來幫助我們將 Rust 代碼編譯為 WebAssembly。
這是讀取 DNA 測序數據並輸出帶有質量指標摘要的 JSON 的代碼片段:
// Import packages extern crate wasm_bindgen; use bio::seq_analysis::gc; use bio::io::fastq; ... // This "wasm_bindgen" tag lets us denote the functions // we want to expose in our WebAssembly module #[wasm_bindgen] pub fn fastq_metrics(seq: String) -> String { ... // Loop through lines in the file let reader = fastq::Reader::new(seq.as_bytes()); for result in reader.records() { let record = result.unwrap(); let sequence = record.seq(); // Calculate simple statistics on each record n_reads += 1.0; let read_length = sequence.len(); let read_gc = gc::gc_content(sequence); // We want to draw histograms of these values // so we store their values for later plotting hist_gc.push(read_gc * 100.0); hist_len.push(read_length); ... } // Return statistics as a JSON blob json!({ "n": n_reads, "hist": { "gc": hist_gc, "len": hist_len }, ... }).to_string() }
然後,我們使用 Cloudflare 的 wrangler 命令行工具來完成編譯到 WebAssembly 和部署到雲的繁重工作。 完成後,我們將獲得一個 API 端點,該端點將排序數據作為輸入並返回帶有數據質量指標的 JSON。 我們現在可以將該 API 集成到我們的應用程序中。
這是應用程序的 GIF 動圖:
完整代碼可在 GitHub(開源)上獲得。
把它放在上下文中
為了將無服務器 WebAssembly 方法放在上下文中,讓我們考慮構建數據處理 Web 應用程序(即我們對用戶提供的數據執行分析的 Web 應用程序)的四種主要方式:
如上圖,數據處理可以在幾個地方進行:
- 服務器端
這是大多數 Web 應用程序採用的方法,在前端進行的 API 調用在後端啟動數據處理。 - 客戶端 JavaScript
在這種方法中,數據處理代碼用 JavaScript 編寫並在瀏覽器中運行。 缺點是你的性能會受到影響,如果你的原始代碼不是用 JavaScript 編寫的,你需要從頭開始重寫它! - 客戶端 WebAssembly
這涉及將數據分析代碼編譯為 WebAssembly 並在瀏覽器中運行。 如果分析代碼是用 C、C++ 或 Rust 等語言編寫的(這在我的基因組學領域很常見),那麼就不需要用 JavaScript 重寫複雜的算法。 它還提供了加速我們的應用程序的潛力(例如,如前一篇文章中所討論的)。 - 無服務器 WebAssembly
這涉及使用 FaaS 類型的模型(例如本文)在雲上運行已編譯的 WebAssembly。
那麼,為什麼您會選擇無服務器方法而不是其他方法呢? 一方面,與第一種方法相比,它具有使用 WebAssembly 帶來的好處,尤其是能夠移植現有代碼而無需將其重寫為 JavaScript。 與第三種方法相比,無服務器 WebAssembly 還意味著我們的應用程序更輕量級,因為我們不使用用戶的資源進行數字運算。 特別是,如果計算相當複雜,或者數據已經在雲中,這種方法更有意義。
但是,另一方面,應用程序現在需要建立網絡連接,因此應用程序可能會變慢。 此外,根據計算的規模以及是否可以將其分解為更小的分析塊,由於無服務器雲提供商對運行時、CPU 和 RAM 利用率的限制,這種方法可能不適合。
結論
正如我們所看到的,現在可以以無服務器方式運行 WebAssembly 代碼,並獲得 WebAssembly(可移植性和速度)和功能即服務架構(自動擴展和按使用定價)的優勢)。 某些類型的應用程序(例如數據分析和圖像處理等)可以從這種方法中受益匪淺。 雖然運行時會因為額外的網絡往返而受到影響,但這種方法確實允許我們一次處理更多數據,而不會消耗用戶的資源。