全部產品
Search
文件中心

Alibaba Cloud Service Mesh:基於網格層跨叢集使用流量鏡像

更新時間:Jun 30, 2024

流量鏡像功能可以將生產的流量鏡像拷貝到測試叢集或者新的測試版本中,在不影響實際生產環境的情況下,測試具有實際生產流量的服務,協助您減低版本變更的風險。本文介紹什麼是流量鏡像,以及如何基於網格層跨叢集使用流量鏡像。

什麼是流量鏡像?

微服務能夠協助使用者快速地開發和部署應用,但版本變更中也存在一定風險。Service MeshASM提供流量鏡像(Traffic Mirroring)的功能,也稱影子流量(Traffic Shadowing)。該功能將即時資料流量的副本發送到鏡像服務,而鏡像流量發生在主服務的關鍵請求路徑之外。當流量被鏡像時,請求將通過其主機或授權前序發送到鏡像服務添加“–shadow”標記,用以區分流量從何處被鏡像到何處。流量鏡像功能可以將生產的流量鏡像拷貝到測試叢集或者新的測試版本中,在引導即時資料流量之前進行測試,有效地降低版本變更的風險。

功能優勢

優勢

說明

測試環境更加真實,版本部署風險更低。

流量鏡像功能可以將生產的流量鏡像拷貝到測試叢集或者新的測試版本中,利用即時生產用例和流量進行測試,使得測試服務環境更加真實,測試結果更加準確,協助您降低生產環境部署的風險。

不影響實際生產環境。

  • 當流量鏡像到不同的服務時,會發生在請求的關鍵路徑之外。流量鏡像產生的任何問題都不會影響生產環境。

  • 忽略對任何鏡像流量的響應,流量被視為“即發即忘”。鏡像執行個體發回的任何響應都將被忽略,不會干擾到正常的生產流量的響應。

適用情境

流量鏡像可以在不影響最終用戶端的情況下,測試具有實際生產流量的服務。您可以使用流量鏡像功能,驗證新版本是否能夠以相同的方式處理真正的各種傳入請求、在同一服務的兩個版本之間進行比較基準測試等。

下面介紹幾種典型的應用情境,協助您發揮流量鏡像的優勢。

應用情境

說明

線上流量類比和測試

測試叢集的測試可以使用生產執行個體真實流量,不會影響正常生產的關鍵路徑。例如,用新系統替換老舊系統或者系統經歷大規模改造時,您可以將線上流量匯入新系統,進行試運行;對於一些實驗性的架構調整,您也可以通過線上流量進行類比測試。

新版本校正

您可以即時對比生產流量和鏡像流量的輸出結果。由於是全樣本的類比,影子流量可以應用於新服務的預上線演練。傳統的手工測試本身是一種樣本化的行為,通過匯入真實流量形態,可以完整地類比線上的所有情況,例如異常的特殊字元、帶惡意攻擊的Token等,協助您探測預發布服務最真實的處理能力和對異常的處理能力。

隔離測試資料庫

與資料處理相關的業務,可以使用空的資料存放區並載入測試資料。針對該資料進行鏡像流量操作,實現測試資料的隔離。

線上問題排查和臨時的資料擷取

對於一些線上突發性問題,線上下流量總是無法複現,此時您可以臨時開啟一個分支服務,匯入影子流量進行調試和排查。採用此方式,不影響線上服務。

日誌行為採集

對於推薦系統和演算法來說,樣本和資料非常核心。傳統的自動化測試在演算法類的應用面臨的最大挑戰是無法構建真實環境的使用者行為資料。通過影子流量可以將使用者行為以日誌的形式儲存起來,既可以為推薦系統和演算法模型構建類比測試樣本資料,也可以作為後續巨量資料分析使用者畫像的資料來源再應用到建議服務中。

啟用流量鏡像範例程式碼

使用Istio啟用流量鏡像的YAML樣本如下。YAML樣本中,VirtualService將100%的流量路由到v1子集,同時將相同的流量鏡像到v1-mirroring子集。發送給v1子集的相同請求將被複製並觸發v1-mirroring子集。

當v1-mirroring將一些請求發送到應用程式的v1版本時,您可以查看應用程式的日誌。調用應用程式時,獲得的響應來自v1子集。您還可以看到請求鏡像到v1-mirroring子集。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-traffic-mirroring
spec:
  hosts:
    - myapp
  http:
    - route:
        - destination:
            host: myapp.default.svc.cluster.local
            port:
              number: 8000
            subset: v1
          weight: 100
      mirror:
        host: myapp.default.svc.cluster.local
        port:
          number: 8000
        subset: v1-mirroring

跨叢集使用流量鏡像流程介紹

基於網格層使用流量鏡像一般多用於為預發布環境匯入線上真實流量的情境,因此在跨叢集中比較常見。本文以生產環境的叢集(clusterA)和測試叢集(clusterB)為例,主體請求在生產環境的叢集clusterA上,由它的網關將流量鏡像拷貝到叢集clusterB中。基於叢集內服務層使用流量鏡像

步驟一:在測試叢集中配置並啟動樣本應用服務

  1. 使用以下內容,建立httpbin.yaml檔案。

    展開查看httpbin.yaml

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: httpbin
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: httpbin
      labels:
        app: httpbin
        service: httpbin
    spec:
      ports:
      - name: http
        port: 8000
        targetPort: 80
      selector:
        app: httpbin
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin-v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: httpbin
          version: v1
      template:
        metadata:
          labels:
            app: httpbin
            version: v1
        spec:
          serviceAccountName: httpbin
          containers:
          - image: docker.io/kennethreitz/httpbin
            imagePullPolicy: IfNotPresent
            name: httpbin
            ports:
            - containerPort: 80
    ---
  2. 執行以下命令,部署v1版本的httpbin服務。

    kubectl apply -f httpbin.yaml

步驟二:在測試叢集中配置網關路由規則

  1. 使用以下內容,建立httpbin-gateway.yaml檔案。

    展開查看httpbin-gateway.yaml

    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: httpbin-gateway
    spec:
      selector:
        istio: ingressgateway
      servers:
      - port:
          number: 80
          name: http
          protocol: HTTP
        hosts:
        - "*"
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: httpbin
    spec:
      hosts:
      - "*"
      gateways:
      - httpbin-gateway
      http:
      - match:
        - uri:
            prefix: /headers
        route:
        - destination:
            host: httpbin
            port:
              number: 8000
  2. 執行以下命令,部署網關路由規則。

    kubectl apply -f httpbin-gateway.yaml
  3. 執行以下命令,訪問測試叢集clusterB中的入口網關,查看服務是否正常工作。

    curl http://{clusterB叢集的入口網關地址}/headers

    樣本輸出:

    {
      "headers": {
        "Accept": "*/*",
        "Host": "47.99.XX.XX",
        "User-Agent": "curl/7.79.1",
        "X-Envoy-Attempt-Count": "1",
        "X-Envoy-External-Address": "120.244.XXX.XXX",
        "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=158e4ef69876550c34d10e3bfbd8d43f5ab481b16ba0e90b4e38a2d53ac****;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"
      }
    }

    返回以上結果,表明服務工作正常。

步驟三:在主叢集的網格中配置外部存取規則

鏡像的服務主機是一個外部網域名稱。您需要添加一個ServiceEntry,指定服務主機Host的DNS解析方式。

  1. 使用以下內容,建立httpbin-cluster-b.yaml檔案。

    apiVersion: networking.istio.io/v1alpha3
    kind: ServiceEntry
    metadata:
      name: httpbin-cluster-b
    spec:
      hosts:
      - httpbin.mirror.cluster-b
      location: MESH_EXTERNAL
      ports:
      - number: 80   # 注意此處的連接埠值是指向叢集clusterB的入口網關的連接埠80。
        name: http
        protocol: HTTP
      resolution: STATIC
      endpoints:
      - address: 47.95.XX.XX # 注意此處的IP值是指向叢集clusterB的入口網關地址。
  2. 執行以下命令,部署ServiceEntry。

    kubectl apply -f httpbin-cluster-b.yaml
  3. 使用以下內容,建立httpbin-gateway.yaml檔案。

    將100%流量匯入到主叢集clusterA內的httpbin服務的v1版本。同時,將流量鏡像到測試叢集clusterB中的服務,通過訪問網域名稱httpbin.mirror.cluster-b指向外部的服務地址。

    展開查看httpbin-gateway.yaml

    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: httpbin-gateway
    spec:
      selector:
        istio: ingressgateway
      servers:
      - port:
          number: 80
          name: http
          protocol: HTTP
        hosts:
        - "*"
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: httpbin
    spec:
      gateways:
        - httpbin-gateway
      hosts:
        - '*'
      http:
        - match:
            - uri:
                prefix: /headers
          mirror:
            host: httpbin.mirror.cluster-b
            port:
              number: 80
          mirrorPercentage:
            value: 50
          route:
            - destination:
                host: httpbin
                port:
                  number: 8000
                subset: v1
    重要

    發送到httpbin.mirror.cluster-b的流量和到原始目標的流量完全相同,只有host/authority要求標頭會被加上-shadow的尾碼。上述樣本中,鏡像流量的host/authority要求標頭並不是httpbin.mirror.cluster-b,而是原始請求Header加上-shadow尾碼。YAML中配置的mirror.host,僅用於尋找轉寄的目的地址,並不會修改原始host Header。

  4. 執行以下命令,部署路由策略。

    kubectl apply -f httpbin-gateway.yaml
  5. 查看主叢集中入口網關Pod中的Envoy config_dump

    "routes": [
             {
              "match": {
               "prefix": "/headers",
               "case_sensitive": true
              },
              "route": {
               "cluster": "outbound|8000|v1|httpbin.default.svc.cluster.local",
               "timeout": "0s",
               "retry_policy": {
                "retry_on": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes",
                "num_retries": 2,
                "retry_host_predicate": [
                 {
                  "name": "envoy.retry_host_predicates.previous_hosts",
                  "typed_config": {
                   "@type": "type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate"
                  }
                 }
                ],
                "host_selection_retry_max_attempts": "5",
                "retriable_status_codes": [
                 503
                ]
               },
               "request_mirror_policies": [
                {
                 "cluster": "outbound|80||httpbin.mirror.cluster-b",
                 "runtime_fraction": {
                  "default_value": {
                   "numerator": 500000,
                   "denominator": "MILLION"
                  }
                 },
                 "trace_sampled": false
                }
               ],

    上述範例程式碼中,request_mirror_policies片段定義請求流量鏡像的策略。樣本中,cluster表示流量鏡像的目標上遊服務;runtime_fraction定義流量鏡像的比例,即通過numerator欄位和denominator欄位來表示百萬分之500000,也就是50%。