Higress 全新 Wasm 執行時,效能大幅提升

阿里云云栖号發表於2024-05-08

本文介紹 Higress 將 Wasm 外掛的執行時從 V8 切換到 WebAssembly Micro Runtime (WAMR) 的最新進展。透過切換到 WAMR 並開啟 AOT 模式大幅提升了 Wasm 外掛效能,從我們的測試中大部分外掛平均有 50% 左右的效能提升,一些邏輯複雜的外掛效能直接翻倍。

Higress Wasm 外掛

Higress 作為首個推出 Wasm 擴充套件能力的雲產品閘道器,從 2022 年就上線了 Wasm 外掛市場,我們使用 Wasm 技術作為主要的閘道器擴充套件手段,是因為它能為使用者帶來的獨特價值:

1. 工程可靠性:相比 Lua 等動態型別+解釋執行語言,Wasm 可基於多種靜態型別語言編譯,可以做編譯期檢查,避免執行時出錯把生產環境變成程式碼捉蟲現場。

2. 沙箱安全性:Wasm 外掛執行在嚴格的虛擬機器沙箱環境內,有自己的獨立記憶體空間,不能直接訪問外部記憶體,可以避免外掛程式碼 bug 導致遭到緩衝區溢位、遠端程式碼執行等攻擊。

3. 熱更新:Higress 基於 Envoy 的 xDS 機制,外掛二進位制和配置都可以獨立熱更新,不會引起連線斷開,對 WebSocket/gRPC 等業務場景更友好。

Higress 站在 Istio/Envoy 的肩膀上,為 Wasm 外掛機制增加了三個核心能力:

1. 域名/路由級生效:Istio/Envoy 自帶的全域性生效方式難以滿足大部分場景需求,而基於 Higress Wasm sdk 開發的外掛可以做到這點,同時編譯出的外掛也跟 Istio/Envoy 生態相容(僅全域性生效)。

2. Redis 訪問能力:提供了訪問 Redis 的 Host Function,外掛程式碼可以基於 Redis 實現多種能力,例如全侷限流,Session 狀態管理等。

3. 虛擬機器自愈機制:開發的外掛邏輯中若出現了空指標訪問、陣列越界、記憶體洩漏等問題,將被執行時系統捕獲,不會導致閘道器崩潰;Higress 支援 Wasm 模組異常後自動重啟,並能在快速止血的同時,透過告警通知使用者出現問題的程式碼堆疊。

從 Higress 的企業使用者看 Wasm 外掛技術的採用週期,已經跨域過鴻溝,步入早期採用大眾階段,核心的驅動力是效能紅利帶來的成本下降。使用者使用 Wasm 外掛來開發滿足自己特定業務需求的能力,對於鑑權、加解密、會話管理等邏輯在閘道器完成計算資源的解除安裝,無需後端服務處理,從而全域性降低計算成本。

效能資料上,之前發表的這篇文件《透過Higress Wasm外掛3倍效能實現Spring Cloud Gateway功能》反饋了過去的效能成果。

在 Higress 將 Wasm 執行時從 V8 替換為 WAMR 後,Wasm 外掛的效能對比之前又有了大幅提升。

Wasm 執行時升級:從 V8 到 WAMR

V8 存在的問題

Wasm 技術誕生於瀏覽器場景,作為 Chromium 的 JS 引擎,V8 是最早支援 Wasm 的執行時之一,V8 引擎基於 JIT 模式執行 Wasm 模組,有著很好的效能。但也存在以下問題:

1. V8 專案複雜度很高:Wasm 相關實現跟 JS 處理邏輯有較多耦合,比如早期的 Envoy Wasm 外掛的一個 bug 就是 V8 為最佳化 JS 執行記憶體引入指標壓縮導致。

bug:https://bugs.chromium.org/p/v8/issues/detail?id=12592

2. V8 社群和 Envoy 社群之間缺少協作:Envoy 目前對於 V8 的版本依賴還停留在 2022 年的提交,無法支援 Wasm GC 等新特性,因為專案複雜度高,升級 V8 依賴的風險也很高。

3. 客戶端偏好:V8 的使用者和開發者大多來自客戶端,考慮裝置相容性,更重視 JIT 模式的最佳化,AOT 模式下效能提升不大,無法完全發揮 Wasm 效能優勢。

WAMR 的優勢

WAMR 是最早由 Intel 團隊開發,在位元組碼聯盟(Bytecode Alliance,面向 Wasm 軟體生態的非盈利組織)下的一個廣受歡迎的 WebAssembly 執行時開源專案。目前社群活躍的貢獻者包含來自 Intel、小米、亞馬遜、索尼、Midokura、西門子、螞蟻等公司的工程師。WAMR 使用 C 語言開發,具有良好的平臺適應性。支援解釋模式、即時編譯及預編譯等模式執行 Wasm 模組,有著優良的效能,在多個公開效能測評報告中均表現優異,同時又極低的資源開銷,可以在 100KB 記憶體中執行單個 Wasm 例項。

效能對比

  • 壓測工具:k6
  • 伺服器 CPU 型號:Intel(R) Xeon(R) Platinum 8369B CPU @ 2.90GHz
  • 壓測方式:Higress 啟動 2 個 worker 執行緒,壓測期間固定 k6 的壓力,跑滿兩個執行緒

選取了部分 Higress 外掛進行效能測試,情況如下:

外掛名稱 外掛用途 V8
(ms)
WAMR
(ms)
效能提升
bot-detect 基於正則識別阻止網際網路爬蟲對站點資源的爬取 1.25 0.64 95%
hmac-auth 基於HMAC演算法為HTTP請求生成不可偽造的簽名,
並基於簽名實現身份認證和鑑權
4.44 3.25 36%
jwt-auth 基於JWT(JSON Web Tokens)進行認證鑑權 11.98 7.46 60%
jwt-logout 基於Redis實現JWT的弱狀態管理,解決JWT無法登出的問題 14.08 8.44 66%
key-auth 基於 API Key 進行認證鑑權 1.66 1.16 43%
oauth 基於JWT進行OAuth2 Access Token簽發 10.15 4.75 113%

注:表格中的資料為單請求平均附加延時

整體來看,Wasm 指令越複雜的外掛,WAMR 的提升越明顯。上述所有外掛除 jwt-logout 是企業版外掛未開源以外,其餘外掛均可以在 Higress 開源倉庫目錄下檢視對應原始碼實現:https://github.com/alibaba/higress/tree/main/plugins/wasm-cpp/extensions

編譯生成 AOT 檔案,可以使用 wamrc 這個 WAMR 提供的官方編譯工具:wamrc --invoke-c-api-import -o plugin.aot plugin.wasm。

為了生成的 wasm 檔案可以相容 JIT 模式,使用 WAMR 倉庫下的指令碼生成合並檔案:python3 wasm-micro-runtime/test-tools/append-aot-to-wasm/append_aot_to_wasm.py --aot plugin.aot --wasm plugin.wasm -o plugin.aot.wasm

以提升最大的 oauth 外掛為例,可以使用下述配置進行復現:

k6 壓測命令:k6 run --vus 300 ./script.js --duration 60s

k6 壓測指令碼:

import http from 'k6/http';
import { check } from 'k6';

export default function () {
    const res = http.get('http://11.164.3.16:10000/',{headers: {'Authorization':'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6ImFwcGxpY2F0aW9uL2F0K2p3dCJ9.eyJhdWQiOiJ0ZXN0MiIsImNsaWVudF9pZCI6Ijk1MTViNTY0LTBiMWQtMTFlZS05YzRjLTAwMTYzZTEyNTBiNSIsImV4cCI6MTY2NTY3MzgyOSwiaWF0IjoxNjY1NjczODE5LCJpc3MiOiJIaWdyZXNzLUdhdGV3YXkiLCJqdGkiOiIxMDk1OWQxYi04ZDYxLTRkZWMtYmVhNy05NDgxMDM3NWI2M2MiLCJzY29wZSI6InRlc3QiLCJzdWIiOiJjb25zdW1lcjEifQ.LsZ6mlRxlaqWa0IAZgmGVuDgypRbctkTcOyoCxqLrHY'}});
    check(res, { 'status was 200': (r) => r.status == 200 });
}

envoy 配置片段:

                  - name: envoy.filters.http.wasm
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
                      config:
                        name: "my_plugin"
                        configuration:
                          "@type": "type.googleapis.com/google.protobuf.StringValue"
                          value: |
                            {
                                "consumers": [
                                    {
                                        "name": "consumer1",
                                        "client_id": "9515b564-0b1d-11ee-9c4c-00163e1250b5",
                                        "client_secret": "9e55de56-0b1d-11ee-b8ec-00163e1250b5"
                                    }
                                ],
                                "clock_skew_seconds": 3153600000
                            }
                        vm_config:
                          runtime: envoy.wasm.runtime.wamr
                          #runtime: envoy.wasm.runtime.v8
                          code:
                            local:
                             filename: "oauth.aot.wasm"
                          allow_precompiled: true

效能提升原因

主要的原因包含:

1. WAMR 提供了深度最佳化的預編譯的能力。在部署前,WAMR 將 Wasm opcodes 翻譯為 IR,經過定製的最佳化流水線,生成指定平臺的機器碼。在執行時,執行預編譯後的 Wasm 可以獲得媲美 native binary 的效能。

2. WAMR 採用了高度最佳化的 FFI。有效降低在 host(c/c++) 和 guest(wasm) 兩個世界間“穿梭”時需要的型別轉換和記憶體複製的次數,減少不必要的損耗。

3. WAMR 可以智慧感知平臺的硬體加速能力並予以充分利用。比如當執行在 X86 平臺時,WAMR 實現了學術界最新提出的 "segue" 演算法,利用 GS 暫存器作為定址方法,提升了訪問 Wasm 線性空間的效率。

未來展望

在 Higress 團隊和 WAMR 團隊之間的緊密協作下,除了在閘道器場景提升 Wasm 外掛效能,還帶來了很多實用的新特性即將釋出,敬請期待:

1. 支援生成 CPU 火焰圖,例如下面是 Wasm 外掛中執行 fibonacci 遞迴看到的 CPU 火焰圖:

Higress 全新 Wasm 執行時,效能大幅提升

2. 支援 Wasm 外掛中邏輯問題導致 Crash 後,外掛日誌中列印完整的函式堆疊,並可以透過 WAMR 提供的 addr2line 工具定位到原始碼中的具體行號。

3. 支援觀測每個 Wasm 外掛模組的 CPU 和記憶體佔用情況。

4. 支援使用 TypeScript 編寫 Wasm 外掛,完整語法支援。

歡迎更多開發者一起參與 Higress 和 WAMR 開源社群,GitHub 專案地址:

Higress:https://github.com/alibaba/higress

WAMR:https://github.com/bytecodealliance/wasm-micro-runtime

本文作者:

澄潭,阿里雲 API 閘道器軟體工程師,Higress 開源專案主要貢獻者

何良,Intel Web Platform Engineering 軟體工程師,WAMR 開源專案主要貢獻者

原文連結

本文為阿里雲原創內容,未經允許不得轉載。

相關文章