全部產品
Search
文件中心

Alibaba Cloud Service Mesh:使用指數加權移動平均(EWMA)實現基於工作負載延遲的負載平衡

更新時間:Oct 09, 2024

ASM在1.21版本提供了Peak EWMA(Exponentially Weighted Moving Average)負載平衡器,該負載平衡器通過計算靜態權重、延遲、錯誤率等的移動平均值得出節點的分值進行負載平衡選擇。當後端服務需要處理突然增加的流量時,ASM可以通過Peak EWMA演算法關注執行個體的最高負載和即時回應時間,靈活地對流量進行分配,從而更好地處理流量峰值。本文介紹如何配置和使用指數加權移動平均(EWMA)實現基於工作負載延遲的負載平衡。

背景資訊

服務網格ASM提供了多種常見的負載平衡演算法,包括輪詢、最少請求數、隨機等。這些演算法可以滿足大多數業務情境的需求,並保證一定的效能表現。但是這些演算法只能根據靜態規則來進行後端選擇,不會考慮後端執行個體的即時狀態和效能。

例如,某網格使用預設的負載平衡演算法,其後端服務的一個Pod由於所在的宿主機資源被其他應用佔用而響應遲緩,導致請求延時增加甚至逾時,而其他幾個Pod則相對空閑。在這種情況下,如果負載平衡器能智能地避開這個效能異常的Pod,將流量更多地路由至其他相對閒置Pod,這樣可以顯著地降低應用整體的錯誤率和響應延遲。

前提條件

使用方法

  1. 登入ASM控制台,在左側導覽列,選擇服務網格 > 網格管理

  2. 網格管理頁面,單擊目標執行個體名稱,然後在左側導覽列,選擇流量管理中心 > 目標規則,然後單擊使用YAML建立

  3. 填入以下樣本內容,單擊建立。此樣本YAML為命名空間default下的服務simple-server指定了PEAK_EWMA負載平衡演算法。

    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: simple-server
      namespace: default
    spec:
      host: simple-server.default.svc.cluster.local
      trafficPolicy:
        loadBalancer:
          simple: PEAK_EWMA # 指定使用ASM PEAK_EWMA負載平衡器

使用樣本

樣本介紹

本樣本使用simple-server應用作為服務端,sleep應用作為發起測試流量的用戶端,基於simple-server應用的服務simple-server.default.svc.cluster.local服務作為服務端。該服務下包含兩個不同配置的deployment:

  • simple-server-normal:該Deployment配置返回延遲範圍50~100ms。

  • simple-server-hight-latency:該Deployment配置返回延遲範圍為500~2000ms,使用該deployment來類比一個服務下部分工作負載延遲增高的情況。

步驟一:為ASM執行個體啟用監控指標

為了更加直觀地體現Peak EWMA負載平衡器的效果,本樣本通過啟用ASM監控指標來觀察啟用Peak EWMA負載平衡前後服務整體回應時間變化。關於啟用監控指標以及採集監控指標到ARMS,請參見將監控指標採集到可觀測監控Prometheus版

步驟二:環境部署

  1. 在ACK叢集對應的KubeConfig環境下,使用以下YAML建立sleep.yaml。

    展開查看YAML內容

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: sleep
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: sleep
      labels:
        app: sleep
        service: sleep
    spec:
      ports:
      - port: 80
        name: http
      selector:
        app: sleep
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sleep
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sleep
      template:
        metadata:
          labels:
            app: sleep
        spec:
          terminationGracePeriodSeconds: 0
          serviceAccountName: sleep
          containers:
          - name: sleep
            image: curlimages/curl
            command: ["/bin/sleep", "infinity"]
            imagePullPolicy: IfNotPresent
            volumeMounts:
            - mountPath: /etc/sleep/tls
              name: secret-volume
          volumes:
          - name: secret-volume
            secret:
              secretName: sleep-secret
              optional: true
    ---

    執行以下命令,部署sleep應用。

    kubectl apply -f sleep.yaml
  2. 使用以下內容建立simple.yaml。

    展開查看YAML內容

    apiVersion: v1
    kind: Service
    metadata:
      name: simple-server
      labels:
        app: simple-server
        service: simple-server
    spec:
      ports:
      - port: 8080
        name: http
      selector:
        app: simple-server
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: simple-server
      name: simple-server-normal
      namespace: default
    spec:
      progressDeadlineSeconds: 600
      replicas: 1
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: simple-server
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: simple-server
        spec:
          containers:
          - args:
            - --delayMin
            - "50"
            - --delayMax
            - "100"
            image: registry-cn-hangzhou.ack.aliyuncs.com/test-public/simple-server:v1.0.0.0-g88293ca-aliyun
            imagePullPolicy: IfNotPresent
            name: simple-server
            ports:
            - containerPort: 80
              protocol: TCP
            resources:
              limits:
                cpu: 500m
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: simple-server
      name: simple-server-high-latency
      namespace: default
    spec:
      progressDeadlineSeconds: 600
      replicas: 1
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: simple-server
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: simple-server
        spec:
          containers:
          - args:
            - --delayMin
            - "500"
            - --delayMax
            - "2000"
            image: registry-cn-hangzhou.ack.aliyuncs.com/test-public/simple-server:v1.0.0.0-g88293ca-aliyun
            imagePullPolicy: IfNotPresent
            name: simple-server
            ports:
            - containerPort: 80
              protocol: TCP
            resources:
              limits:
                cpu: 500m
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
    ---

    執行以下命令部署simple-server-normal和simple-server-high-latency應用。

    kubectl apply -f simple.yaml

步驟三:以預設負載平衡演算法發起測試

本節是基於預設負載平衡演算法LEAST_REQUEST產生基準資料。

  1. 執行以下命令發起測試,該命令會向simple-server服務發起100次/hello調用:

    kubectl exec -it deploy/sleep -c sleep --  sh -c 'for i in $(seq 1 100); do time curl simple-server:8080/hello; echo "request $i done"; done'

    預期輸出如下:

    hello
     this is port: 8080real 0m 0.06s
    user    0m 0.00s
    sys     0m 0.00s
    request 1 done
    hello
     this is port: 8080real 0m 0.09s
    user    0m 0.00s
    sys     0m 0.00s
    request 2 done
    
    ......
    
    hello
     this is port: 8080real 0m 1.72s
    user    0m 0.00s
    sys     0m 0.00s
    request 100 done
  2. 命令執行完畢後,在網格管理頁面,單擊目標執行個體名稱,然後在左側導覽列,選擇可觀測管理中心 > 監控指標,選擇網格服務等級監控選項卡,輸入以下篩選條件:

    • Namespace: default

    • Service: simple-server.default.svc.cluster.local

    • Reporter: destination

    • Client Workload Namespace: default

    • Client Workload: sleep

    • Service Workload Namespace: default

    • Service Workload: simple-server-normal + simple-server-high-latency

  3. 單擊Client Workloads下拉式功能表,查看Incoming Request Duration By Source面板。

    image

    可以看到,sleep應用到simple-server服務的請求回應時間P50為87.5ms,P95則上升較為顯著,達到了2.05s,這是因為simple-server-high-latency的延遲較高,增加了整個服務的回應時間。

    重要

    上述步驟中提到的測試結果是在受控實驗環境下得出的理論數值,實際結果可能會因您的業務環境不同而有所差異。

步驟四:配置Peak EWMA負載平衡演算法再次測試

建立DestinationRule為simple-server服務應用配置Peak EWMA負載平衡演算法。

  1. 參考使用方法中的步驟和以下YAML內容建立目標規則。

    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: simple-server
      namespace: default
    spec:
      host: simple-server.default.svc.cluster.local
      trafficPolicy:
        loadBalancer:
          simple: PEAK_EWMA
  2. 在ACK叢集對應的KubeConfig環境下,執行以下命令再次發起測試。

    kubectl exec -it deploy/sleep -c sleep --  sh -c 'for i in $(seq 1 100); do time curl simple-server:8080/hello; echo "request $i done"; done'
  3. 對照步驟三中查看監控指標的步驟及結果,可以看到P90、P95、P99回應時間明顯下降。這是因為Peak EWMA負載平衡器發現了simple-server-high-latency工作負載的延遲較高,降低了它的負載平衡權重,從而將更多的請求分配至延遲更低的simple-server-normal,從服務整體的視角觀察,請求的整體延遲顯著降低了。

    image