適應多樣化需求:WASM 插件在全鏈路灰度發佈中的應用

作者:十眠

據調研數據顯示,約 70% 的生產故障是由變更引起的。爲了消除變更過程存在的風險,在發佈過程中,我們總是希望能夠用小部分特定流量來驗證下新發布應用是否正常。即使新版本有問題,也能及時發現,控制影響面,保障了整體的穩定性,這就是微服務架構下的全鏈路灰度的能力。

MSE 在微服務全鏈路灰度場景下提供了一套成熟完善且開箱即用的能力。

隨着企業微服務化改造的深入,對微服務治理的場景與應用也有了更多的訴求,全鏈路灰度就是如此。MSE 默認支持按照內容規則與百分比規則的灰度路由策略,其中按照內容灰度支持 header、params 等參數件支持精確/前綴/正則等多種匹配策略,滿足常見全鏈路灰度場景的訴求。如果我們遇到較爲複雜的場景,發現 MSE 提供的策略無法滿足我們訴求時,應該怎麼解決?

接下來,我們來一起討論幾個合理且較爲複雜的灰度需求。

很多複雜且合理的灰度訴求

其實關於全鏈路灰度有其他很多合理的訴求,比如:

  1. 我們希望隨機百分比可以根據參數特徵來調整,這樣對於每個用戶來說,是否被灰度是固定的,多次調用體驗一致。

  2. 我們來自於手機客戶端的流量帶有 version 特徵、來自網頁流量又是帶有 tag 的特徵,我們期望兩者滿足任一條件的流量去往灰度環境即流量條件匹配爲“或”的模式;

  3. 來自我們生產流量確實比較大,我們期望第一批灰度的流量可以控制到整體 1‰ 流量的灰度訴求;

  4. 我們期望可以基於流量 Body 參數解析的灰度訴求。

面對一系列複雜並帶有定製需求的合理訴求,產品層面很難做到完全支持。這些訴求在企業客戶的生產實際中非常常見,而當前的 MSE 控制檯配置方案似乎並不能完美應對這些多樣化的實際場景。畢竟,當我們將目光轉向不同企業客戶的生產實踐時,會發現複雜場景的變化和多樣性只會更加顯著。那麼,我們如何能夠有效地滿足複雜環境下全鏈路灰度發佈的訴求呢?

雲原生網關 WASM 插件

什麼是 WASM?WASM(WebAssembly)是一種可移植、高性能的二進制指令集,用於在 Web 瀏覽器中運行代碼。Envoy 使用 WASM 作爲插件擴展機制,允許開發人員編寫自定義的功能擴展,以滿足特定的需求。

雲原生網關 WASM 插件擴展機制的工作原理如下:

  1. MSE 雲原生網關提供了插件市場,供我們編寫自定義的 WASM 插件來滿足各種擴展的訴求,如請求/響應轉換、過濾器、身份驗證等。同時編寫 WASM 插件支持(Go、Rust、類 JS、lua 等)。

  2. 我們只需要將編譯好的 WASM 文件通過自定義插件的方式上傳到插件市場,MSE 雲原生網關會將其加載到 Envoy 中。

  3. 當雲原生網關處理網絡流量時,它會根據配置將流量傳遞給適當的 WASM 插件進行處理,即上圖的 Custom Filters。WASM 插件可以讀取和修改請求/響應數據,執行自定義邏輯,並將流量傳遞給下一個插件或最終目標。

MSE 插件市場還提供了一些默認認證鑑權、流量管控、安全防護等平臺官方插件,可以幫助我們提升網關的安全與穩定性,並且支持多語言自定義擴展,滿足網關上自定義流量治理需求。

MSE WASM 插件擴展機制的優點包括:

  1. 藉助 WASM 特性支持多語言擴展,提供了靈活性和可擴展性,可以通過 WASM 插件編寫開發,滿足特定的業務需求。

  2. 網關 Wasm 插件與開源 Envoy100% 兼容,不存在鎖定。

  3. 提供插件市場,網關的二次擴展功能均通過插件提供給用戶按需使用。

  4. 插件採用熱更新機制,在沙盒中執行,對網關自身穩定性無影響。

WASM 插件以其獨特的輕量級和高效性能特點,爲雲原生網關帶來了創新的擴展能力,而這一切不會帶來明顯的性能開銷。WASM 插件運行在沙箱環境中,提供了一種安全可控的方式來部署自定義邏輯,這樣不僅保障了網關的靈活性和可擴展性,也確保了對整體性能的最小影響。

看起來 MSE 雲原生網關的 WASM 插件確實是一種優雅且便捷的方式,能夠滿足各種全鏈路灰度的需求。接下來,我將通過編寫 WASM 插件來實現在複雜條件下的全鏈路灰度。

通過 WASM 插件實現參數比例

上文提到,WASM 插件可以支持多語言擴展,我們可以選擇我們擅長的語言進行開發,本文以 Go 語言爲例。

雲原生網關提供了 wrapper 包以及相關的 API 供我們快速編寫 WASM 插件。

  1. 雲原生網關配置基於 x-mse-tag 的灰度路由,詳見基於 MSE 雲原生網關實現全鏈路灰度 [ 1]

服務治理泳道配置如下:

雲原生網關路由配置如下:

我們創建灰度泳道,只要 header 中存在 x-mse-tag=gray 的請求都會被認爲是灰度流量,且在後續鏈路中都會優先去往灰度環境。因此在 WASM 插件中,我們可以對流量進行任意自定義的計算和匹配。只要符合我們的灰度條件,我們就可以在請求頭中添加一個名爲 "x-mse-tag" 值爲 "gray" 的標識。這樣,我們就可以對灰度流量進行標記和識別。

  1. 定義插件擴展配置。
type ParamsRandomConfig struct {
    # 參數比例功能開關
    paramsRandomEnable    bool
    # 參數比例依據哪個Header的值,例如userId
  paramsRandomHeaderKey string
    # 參數比例的百分比值,
    paramsPercentageRatio     int64
}
  1. 解析插件擴展參數,在控制檯插件配置中填寫的 YAML 配置會自動轉換爲 JSON,此處直接從 JSON 這個參數裏解析配置即可。
// 在控制檯插件配置中填寫的YAML配置會自動轉換爲JSON,此處直接從JSON這個參數裏解析配置即可
func parseConfig(json gjson.Result, config *MyConfig, log wrapper.Log) error {
  // 解析出配置,更新到config中
  config.paramsRandomEnable = json.Get("paramsRandomEnable").Bool()
  config.paramsRandomHeaderKey = json.Get("paramsRandomHeaderKey").String()
  config.paramsPercentageRatio = json.Get("paramsPercentageRatio").Int()

  return nil
}
  1. 請求處理 Filter 編寫。
func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig, log wrapper.Log) types.Action {
  if config.paramsRandomEnable {
    randomHeaderValue, err := proxywasm.GetHttpRequestHeader(config.paramsRandomHeaderKey)
    if err != nil {
      proxywasm.LogErrorf("get header enhance error: %v", err)
      return types.ActionContinue
    }

    // 取目標參數值的 hash ,用於百分比值計算
    hash := sha256.Sum256([]byte(randomHeaderValue))
    hashInt := new(big.Int)
    hashInt.SetBytes(hash[:])

    modulo := new(big.Int).Mod(hashInt, big.NewInt(100))
    result := modulo.Cmp(big.NewInt(config.paramsPercentageRatio))
    if result <= 0 {
      // 寫入 x-mse-tag=gray 說明該請求流量標爲 gray,在後續鏈路中會優先去玩gray環境的節點,
      // 如果對應的應用沒有gray環境,會fallback到基線環境
      proxywasm.AddHttpRequestHeader("x-mse-tag", "gray")
    } else {
      // 不符合灰度條件的流量
      proxywasm.LogInfof("set header false value: %s, hash: %s", randomHeaderValue, hashInt)
    }
  }
  return types.ActionContinue
}
  1. 編譯生成 WASM 文件

我們通過如下命令編譯生成 WASM 文件。

go mod tidy
tinygo build -o main.wasm -scheduler=none -target=wasi -gc=custom -tags='custommalloc nottinygc_finalizer' ./main.go

編譯成功會在當前目錄下創建文件 main.wasm。該文件在下文本地調試的示例中也會被用到。

在使用雲原生網關插件市場的自定義插件功能時,直接上傳該文件即可。

  1. 配置參數並驗證參數比例功能

如上圖所示,我們指定 Header 中的 userId 爲百分比依據的參數,並且配置了 10% 流量灰度的比例值。點擊保存後配置,實時生效。

請求過程中 userId=1 的 header 恆定去往灰度環境,userId=11 的請求恆定去往基線環境。

  1. 觀察插件日誌

到目前爲止,我們通過編寫 WASM 插件實現了根據特定 Header 的參數比例需求。

總結

通過 WASM 插件,我們可以實現各種全鏈路灰度的需求,包括但不限於以下幾個方面:

  • 根據用戶標識進行灰度

    可以根據用戶的身份、角色、權限等信息將特定用戶的請求路由到相應的灰度環境,以實現個別用戶的全鏈路灰度。

  • 根據地理位置進行灰度

    可以根據用戶的地理位置信息將請求路由到特定地區的灰度環境,以滿足特定地區的全鏈路灰度需求。

  • 基於流量比例的灰度

    可以根據流量比例將請求路由到不同的灰度環境,以實現按比例分配流量的全鏈路灰度。

  • 基於請求包複雜屬性的灰度

    可以根據請求的屬性,如請求頭、請求體、查詢參數等信息,來判斷是否滿足特定條件,從而路由請求到相應的灰度環境。

利用 WASM 插件的強大適應性,我們可以針對性地編寫插件以適應不同的全鏈路灰度發佈需求。這爲定製化業務場景提供了無限的可能性,使得灰度測試和發佈可以根據獨特的業務要求靈活執行。特別是對於計算密集型和無狀態的任務,如認證鑑權、請求/響應的加密和混淆、內容轉換等,將這些邏輯部署在網關層是理想選擇。它不僅保持了系統的簡潔和靈活性,而且確保了核心網關功能的低性能損失,這在優化資源使用和維護服務品質方面都提供了顯著的好處。

目前 MSE WASM 插件支持 Redis 訪問,當然 WASM 插件也不是萬能的,如果邏輯裏需要對接數據庫,或者要起多線程處理,就不適合做成網關插件,當前 WASM 插件也不支持這些能力。

參考鏈接:

[1] 基於 MSE 雲原生網關實現全鏈路灰度https://help.aliyun.com/zh/mse/user-guide/implement-an-end-to-end-canary-release-by-using-mse-cloud-native-gateways?spm=a2c4g.11186623.0.0.226a5446EBhK5X

[2] 開發插件_微服務引擎(MSE)

https://help.aliyun.com/zh/mse/user-guide/14/?spm=a2c4g.11186623.0.0.73062e8dd0miqK

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章