通過 Higress Wasm 插件 3 倍性能實現 Spring-cloud-gateway 功能

導讀:本文將和大家一同回顧 Spring Cloud Gateway 是如何滿足 HTTP 請求/響應轉換需求場景的,併爲大家介紹在這種場景下使用 Higress 雲原生網關的解決方案,同時還對比了兩者的性能差異。

01 SCG 修改請求/響應

在 Spring Cloud Gateway[1](以下簡稱爲 SCG) 中,當我們需要對 HTTP 請求或響應進行修改時,SCG 提供了許多內置的 GatewayFilter[2]來滿足我們對這種應用場景的需求,例如 AddRequestHeader,AddRequestParameter, DedupeResponseHeader,MapRequestHeader, ModifyRequestBody 等。

考慮以下簡單用例:

  • 添加請求頭部 X-First,值從請求路徑中獲取,例如從 /response-headers?testKey=testValue 中獲取 "response-headers";
  • 將請求頭部 X-First 的值映射給 X-Second;
  • 添加請求查詢參數 k1=v1;
  • 剔除重複的響應頭部 X-Dedupe。

在 SCG 中使用 GatewayFilter 我們可以這樣配置:

# application.yaml:

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: lb://httpbin-svc
          predicates:
            - Path=/{api}/**
          filters:
            - AddRequestHeader=X-First, {api}
            - MapRequestHeader=X-First, X-Second
            - AddRequestParameter=k1, v1
            - DedupeResponseHeader=X-Dedupe, RETAIN_FIRST

相信擁有 SCG 使用經驗的同學對上述配置一定不陌生,那麼本文將重點給出另一種能夠滿足上述需求並且性能更加優越的解決方案——使用 Higress 雲原生網關的 Transformer 插件。

02 Higress 插件與 SCG 性能比較

我們在同一吞吐量水平(QPS)上,開啓/關閉 Higress Transformer 插件[3]和 SCG 相應 GatewayFilters,統計兩者在 CPU 和內存資源上的開銷。

經過測試[13],我們得到的結論是:

  • 在 Higress 未啓用 Transformer 插件,SCG 未啓用 GatewayFilters 的條件下,SCG 的 CPU, 內存資源開銷分別約爲 Higress的 3.30, 4.88倍;
  • 在 Higress 啓用 Transformer 插件,SCG 啓用相應 GatewayFilters 的條件下,SCG 的 CPU,內存資源開銷分別約爲 Higress 的 2.98, 3.19倍。
 

可見 Higress Transformer 相比於 SCG GatewayFilter 有着相當不錯的性能表現!

接下來我們將進一步爲大家介紹 Higress 雲原生網關以及上述提到的 Higress Transformer 插件。

03 Higress 簡介

Higress[4]是基於阿里內部的 Envoy Gateway 實踐沉澱、以開源 Istio + Envoy 爲核心構建的下一代雲原生網關,實現了流量網關+微服務網關+安全網關三合一的高集成能力,深度集成 Dubbo、Nacos、Sentinel 等微服務技術棧,能夠幫助用戶極大地降低網關的部署及運維成本且能力不打折;在標準上全面支持 Ingress 與 Gateway API,積極擁抱雲原生下的標準 API 規範;同時,Higress Controller 也支持 Nginx Ingress 平滑遷移,幫助用戶零成本快速遷移到 Higress。

Higress 提供了一套 Wasm (WebAssembly) SDK[5],使得開發者能夠輕鬆使用 C++,Golang,Rust 開發 Wasm 插件增強網關能力。下面將爲大家介紹 Higress Transformer 插件的基本功能,最後簡單說明 Transformer 插件的核心代碼邏輯。

04 Transformer 插件介紹

Higress Transformer 插件可以對請求/響應頭部、請求查詢參數、請求/響應體參數進行轉換,支持的轉換操作類型包括刪除(remove)、重命名(rename)、更新(replace)、添加(add)、追加(append)、映射(map)和去重(dedupe)。

接下來我們復現最開始提到的 SCG GatewayFilter 簡單用例,來演示如何使用該插件(以下使用 Higress 控制檯可以很方便地部署插件,當然也可以使用 K8s YAML Manifests 的方式[12]):

1. 首先根據官方文檔[6]快速安裝 Higress,結果如下:

$ kubectl -n higress-system get deploy
NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
higress-console              1/1     1            1           1d
higress-console-grafana      1/1     1            1           1d
higress-console-prometheus   1/1     1            1           1d
higress-controller           1/1     1            1           1d
higress-gateway              1/1     1            1           1d

2. 通過 Higress 控制檯添加域名(http://foo.bar.com)、路由配置(foo),將流量轉發至後端的 httpbin[7]服務:

 
 

3. 爲 foo 路由添加 Transformer 插件(當前未推送插件至官方鏡像倉庫,可以先使用 http://docker.io/weixinx/transformer:v0.1.0,或到代碼倉庫自行構建):

注:爲了能夠同時完成請求和響應轉換的需求,我們需要爲 foo 路由再添加一個 Transformer 插件,命名爲 transformer-resp,用於處理響應方向。

4. 添加 Transformer 配置並開啓該插件:

  • 添加請求頭部 X-First,值從請求路徑中獲取,例如從 /response-headers?testKey=testValue 中獲取 "response-headers";
  • 將請求頭部 X-First 的值映射給 X-Second;
  • 添加請求查詢參數 k1=v1;
  • 剔除重複的響應頭部 X-Dedupe。
# transformer:
type: request  # 指定 Transformer 類型
rules:         # 指定轉換規則
- operate: add # 指定轉換操作類型
  headers:     # 指定頭部轉換規則
  - key: X-First
    value: $1  # 正則表達式捕獲組 $1,支持 RE2 語法
    path_pattern: ^\/(\w+)[\?]{0,1}.*$
  querys:      # 指定查詢參數轉換規則
  - key: k1
    value: v1
- operate: map
  headers:
  - key: X-First
    value: X-Second
---
# transformer-resp:
type: response
rules:
- operate: dedupe
  headers:
  - key: X-Dedupe
    value: RETAIN_FIRS

5. 發送請求進行測試:

# 驗證請求方向轉換
$ curl -v -H "host: foo.bar.com" "console.higress.io/get"
...
>
< HTTP/1.1 200 OK
...
<
{
  "args": {
    # 添加了查詢參數 k1=v1
    "k1": "v1"
  },
  "headers": {
    ...
    "X-First": "get", # 添加了請求頭部 X-First,值 "get" 來自請求路徑
    "X-Second": "get" # 映射了請求頭部 X-Second
  },
  ...
  # 添加了查詢參數 k1=v1
  "url": "http://foo.bar.com/get?k1=v1"
}


# 驗證響應方向轉換
$ curl -v -H "host: foo.bar.com" \
"console.higress.io/response-headers?X-Dedupe=1&X-Dedupe=2&X-Dedupe=3"
...
>
< HTTP/1.1 200 OK
< x-dedupe: 1 # 保留了響應頭部 X-Dedupe 的第一個值
...
<
{
  ...
  # 通過查詢參數傳給 httpbin 的自定義響應頭部
  "X-Dedupe": [
    "1",
    "2",
    "3"
  ],
  ...
}

❗️需要注意的是:

  • 與上述例子相同,若有同時處理請求和響應轉換的需求,則需要爲相應路由添加兩個 Transformer 插件,分別處理請求方向和響應方向(正在優化);
  • 請求體支持的 Content-Type 有:application/json,application/x-www-form-urlencoded,multipart/form-data;而響應體僅支持 application/json;
  • 更多說明詳見插件文檔[3]

05 Transformer 邏輯

本節將簡單說明 Higress Transformer 插件的核心代碼邏輯,希望可以爲有興趣優化該插件或進行二次開發的同學提供一些幫助。

首先該插件代碼位於Higress 倉庫的 plugins/wasm-go/extensions/transformer 目錄下,使用 Higress 提供的 Wasm SDK[5]進行開發(關於如何開發 Wasm 插件詳見官方文檔[8])。

插件的配置模型 TransformerConfig:

# 模型以插件配置的形式暴露給用戶
type TransformerConfig struct {
  typ   string          # Transformer 類型,[request, response]
  rules []TransformRule # 轉換規則
  
  trans Transformer # Transformer 實例,不對用戶暴露配置,用於實際的轉換操作
}

type TransformRule struct {
  operate string   # 轉換操作類型
  headers []Param  # header 參數 
  querys  []Param  # query 參數
  body    []Param  # body 參數
}

type Param struct {
  key         string # 表示字段的 key
  value       string # 表示字段的 value 或 key (map) 或 strategy (dedupe)
  valueType   string # 爲 application/json body 指定 value 的數據類型
  hostPattern string # host 正則匹配模式
  pathPattern string # path 正則匹配模式
}

其中 Transformer 作爲接口分別有請求和響應兩個實現(requestTransformer, responseTransformer),主要實現了 3 個接口方法 TransformHeaders,TransformerQuerys 和 TransformBody:

type Transformer interface {
 TransformHeaders(host, path string, hs map[string][]string) error
 TransformQuerys(host, path string, qs map[string][]string) error
 TransformBody(host, path string, body interface{}) error
 ...
}

var _ Transformer = (*requestTransformer)(nil)
var _ Transformer = (*responseTransformer)(nil)

由於頭部(Headers)和查詢參數(Querys)都是以 key-value 的形式存在,因此通過 kvHandler 對兩者採用統一的處理邏輯;而 Body 由於請求、響應支持不同的 Content-Type,因此分別通過 requestBodyHandler (kvHandler,jsonHandler 組合)和 responseBodyHandler (jsonHandler) 進行處理。綜上,在修改該插件邏輯時,主要對kvHandler 和 jsonHandler 進行修改即可,其中 jsonHandler 依賴 GJSON[9]和 SJSON[10]工具庫。

 

 

目前 handler 中的轉換順序是被硬編碼的(remove -> rename -> replace -> add -> append -> map -> dedupe),我們對此有優化的打算,也歡迎感興趣的同學參與進來 ~

06 總結

本文帶大家瞭解了 Higress Transformer 插件,並與 Spring Cloud Gateway 進行了性能比較,在文章的最後還說明了該插件的核心代碼邏輯,希望能夠爲大家從 Spring Cloud Gateway 遷移至 Higress 提供幫助!

相關鏈接:

[1] Spring Cloud Gateway

https://cloud.spring.io/spring-cloud-gateway/reference/html/

[2] SCG GatewayFilter Factories

https://cloud.spring.io/spring-cloud-gateway/reference/html/#gatewayfilter-factories

[3] Higress Transformer 插件

https://github.com/alibaba/higress/tree/main/plugins/wasm-go/extensions/transformer

[4] Higress 官方文檔

https://higress.io/zh-cn/

[5] Higress Wasm SDK

https://github.com/alibaba/higress/tree/main/plugins

[6] Higress 快速開始

https://higress.io/zh-cn/docs/user/quickstart

[7] httpbin

https://httpbin.org/

[8] 開發 Higress Wasm 插件

https://higress.io/zh-cn/docs/user/wasm-go

[9] GJSON

https://github.com/tidwall/gjson

[10] SJSON

https://github.com/tidwall/sjson

[11] Higress 代碼倉庫

https://github.com/alibaba/higress

[12] Transformer Demo

https://github.com/higress-group/higress-demo/tree/main/wasm-demo/wasm-demo-go/wasm-plugin-transformer

[13] 性能對比配置

https://gist.github.com/WeixinX/c24f4ded37832dd7e753b2d27470f0fc

作者:韋鑫,Higress Committer,來自南京航空航天大學分佈式系統實驗室

原文鏈接

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

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