全部產品
Search
文件中心

Alibaba Cloud Service Mesh:使用同可用性區域優先路由

更新時間:Jan 14, 2025

當您遇到跨可用性區域網路延遲導致的服務回應時間增加或成本上升等問題時,可以使用同可用性區域優先路由(簡稱同AZ路由)功能,優先保證服務要求在同一個可用性區域內完成處理,減少網路傳輸延遲,降低因跨地區流量產生的額外費用,提高整體服務的運行效率和穩定性。ASM支援在不需要修改應用代碼的情況下實現同AZ路由。本文以入口網關訪問httpbin應用為例,介紹如何使用同AZ路由。

前提條件

  • 已添加叢集到ASM執行個體。具體操作,請參見添加叢集到ASM執行個體

  • ACK叢集中的節點存在至少兩個可用性區域,本樣本中分別使用cn-hongkong-b和cn-hongkong-c,您可以在Container Service管理主控台查看叢集節點所對應的ECS所在地區及可用性區域。更多資訊,請參見地區和可用性區域

    說明

    本樣本中sleep應用部署在可用性區域cn-hongkong-b,helloworld-v1應用部署到可用性區域cn-hongkong-b中,helloworld-v2應用部署到可用性區域cn-hongkong-c中,您可以根據實際叢集所使用的可用性區域進行替換。

注意事項

同可用性區域優先路由啟用後,在同可用性區域存在可用目標的情況下,叢集內部應用間的調用將不會跨可用性區域。因此,為了保證啟用該能力後的負載平衡,您需要確保相關工作負載是均勻分布在多個可用性區域的。您可以通過topologySpreadConstraints使得工作負載在建立、擴容時被調度器儘可能均勻地分布到不同可用性區域。同時,如果您的工作負載存在擴縮容情境,需要進一步啟用重調度(DeScheduling)以確保在縮容時工作負載仍然保持均勻分布。

背景資訊

同AZ路由是指在用戶端對一個目標服務的訪問過程中,可以根據這個用戶端所在的地區、可用性區域拓撲資訊,優先路由到與該用戶端在同一個節點或者可用性區域的目標服務上的路由行為。同AZ路由本身屬於負載平衡策略的範疇,它能夠使流量儘可能在同一個可用性區域內流轉,以保證服務間的調用延遲最低。

步驟一:部署樣本應用

  1. 使用以下內容,建立sleep.yaml

    說明

    如下樣本中,sleep應用部署到可用性區域cn-hongkong-b,您可以根據實際叢集所使用的可用性區域進行替換。

    展開查看sleep.yaml

    # Copyright Istio Authors
    #
    #   Licensed under the Apache License, Version 2.0 (the "License");
    #   you may not use this file except in compliance with the License.
    #   You may obtain a copy of the License at
    #
    #       http://www.apache.org/licenses/LICENSE-2.0
    #
    #   Unless required by applicable law or agreed to in writing, software
    #   distributed under the License is distributed on an "AS IS" BASIS,
    #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    #   See the License for the specific language governing permissions and
    #   limitations under the License.
    
    ##################################################################################################
    # Sleep service
    ##################################################################################################
    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:
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: failure-domain.beta.kubernetes.io/zone
                    operator: In
                    values:
                      - 'cn-hongkong-b'
          terminationGracePeriodSeconds: 0
          serviceAccountName: sleep
          containers:
          - name: sleep
            image: curlimages/curl
            command: ["/bin/sleep", "3650d"]
            imagePullPolicy: IfNotPresent
            volumeMounts:
            - mountPath: /etc/sleep/tls
              name: secret-volume
          volumes:
          - name: secret-volume
            secret:
              secretName: sleep-secret
              optional: true
  2. 執行以下命令,在叢集中部署sleep應用。

    kubectl apply -f sleep.yaml
  3. 使用以下內容,建立helloworld.yaml

    說明

    如下樣本中,helloworld-v1應用部署到可用性區域cn-hongkong-b中,helloworld-v2應用部署到可用性區域cn-hongkong-c中,您可以根據實際叢集所使用的可用性區域進行替換。

    展開查看helloworld.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: helloworld
      labels:
        app: helloworld
        service: helloworld
    spec:
      ports:
      - port: 5000
        name: http
      selector:
        app: helloworld
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: helloworld-v1
      labels:
        app: helloworld
        version: v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: helloworld
          version: v1
      template:
        metadata:
          labels:
            app: helloworld
            version: v1
        spec:
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: failure-domain.beta.kubernetes.io/zone
                    operator: In
                    values:
                      - 'cn-hongkong-b'
          containers:
          - name: helloworld
            image: docker.io/istio/examples-helloworld-v1
            resources:
              requests:
                cpu: "100m"
            imagePullPolicy: IfNotPresent #Always
            ports:
            - containerPort: 5000
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: helloworld-v2
      labels:
        app: helloworld
        version: v2
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: helloworld
          version: v2
      template:
        metadata:
          labels:
            app: helloworld
            version: v2
        spec:
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: failure-domain.beta.kubernetes.io/zone
                    operator: In
                    values:
                      - 'cn-hongkong-c'
          containers:
          - name: helloworld
            image: docker.io/istio/examples-helloworld-v2
            resources:
              requests:
                cpu: "100m"
            imagePullPolicy: IfNotPresent #Always
            ports:
            - containerPort: 5000
                            
  4. 執行以下命令,在叢集中部署helloworld應用。

    kubectl apply -f helloworld.yaml
  5. 執行以下命令,查詢目標服務的註冊資訊。

    kubectl exec "$(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}')"  -c sleep -- curl localhost:15000/clusters | grep helloworld

    預期輸出:

    outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::region::cn-hongkong
    outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::zone::cn-hongkong-b
    outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::sub_zone::
    outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::canary::false
    outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::priority::0
    .......
    outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::region::cn-hongkong
    outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::zone::cn-hongkong-c
    outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::sub_zone::
    outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::canary::false
    outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::priority::0

    由預期輸出得到,兩個helloworld應用的優先順序相同,均為priority::0。說明當sleep用戶端調用helloworld服務時,兩個helloworld應用的路由策略相同。

步驟二:設定同AZ優先路由

通過應用目標規則來解決優先順序問題,為服務helloworld.default.svc.cluster.local啟用同AZ路由的能力。

說明

您可以調整連續5xx錯誤(consecutive5xxErrors)、間隔時間(interval)以及最小的移除時間長度(baseEjectionTime)參數,實現同可用性區域路由的優先調用。本樣本將在第一個請求失敗時觸發容錯移轉。

  1. 使用以下內容,建立helloworld-failover.yaml

    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: helloworld-failover
      namespace: default
    spec:
      host: helloworld.default.svc.cluster.local
      trafficPolicy:
        connectionPool:
          http:
            maxRequestsPerConnection: 1
        loadBalancer:
          localityLbSetting:
            enabled: true
          simple: ROUND_ROBIN
        outlierDetection:
          baseEjectionTime: 1m
          consecutive5xxErrors: 1
          interval: 1s
                            
  2. 執行以下命令,查看工作負載的優先順序。

    kubectl exec "$(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}')"  -c sleep -- curl localhost:15000/clusters | grep helloworld
                            

    預期輸出:

    outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::region::cn-hongkong
    outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::zone::cn-hongkong-b
    outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::sub_zone::
    outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::canary::false
    outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::priority::0
    .......
    outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::region::cn-hongkong
    outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::zone::cn-hongkong-c
    outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::sub_zone::
    outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::canary::false
    outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::priority::1

    由預期輸出得到,兩個helloworld應用的優先順序不同,分別為priority::0priority::1。說明當sleep用戶端調用helloworld服務時,同AZ路由的策略生效。

步驟三:驗證同AZ優先路由

從位於可用性區域cn-hongkong-b中的用戶端sleep應用發送請求,調用helloworld服務。啟用同AZ優先路由之後,所有流量都應指向同在可用性區域cn-hongkong-b中的helloworld-v1應用。其中,sleep應用部署在可用性區域cn-hongkong-b,helloworld-v1應用部署到可用性區域cn-hongkong-b中,helloworld-v2應用部署到可用性區域cn-hongkong-c中。

  1. 重複執行以下命令,訪問helloworld服務。

    kubectl exec  -c sleep "$(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}')"  -- curl -sSL helloworld:5000/hello

    預期輸出:

    Hello version: v1, instance: helloworld-v1-6f88967849-sq2h2

    由預期輸出得到,返回結果始終為helloworld-v1服務。

  2. 縮容helloworld-v1服務。

    1. 執行以下命令,縮容helloworld-v1服務到0個Pod,類比該服務不可用狀態。

      kubectl scale deploy helloworld-v1 --replicas=0
    2. 等待幾秒後,重複執行以下命令,訪問helloworld服務。

      kubectl exec  -c sleep "$(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}')"  -- curl -sSL helloworld:5000/hello

      預期輸出:

      Hello version: v2, instance: helloworld-v2-75db5f978d-s7v4k

      由預期輸出得到,當本可用性區域的helloworld-v1服務不可用時,會自動切換到另一可用性區域cn-hongkong-c中的helloworld-v2服務。

  3. 擴容helloworld-v1服務。

    1. 執行以下命令,擴容helloworld-v1服務到1個Pod,恢複可用性區域cn-hongkong-b中的helloworld-v1應用服務。

      kubectl scale deploy helloworld-v1 --replicas=1
    2. 等待幾秒後,重複執行以下命令,訪問helloworld服務。

      kubectl exec  -c sleep "$(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}')"  -- curl -sSL helloworld:5000/hello

      預期輸出:

      Hello version: v1, instance: helloworld-v1-6f88967849-sq2h2

      由預期輸出得到,返回結果始終為helloworld-v1服務。