All Products
Search
Document Center

Alibaba Cloud Service Mesh:Enable the zone aware routing feature

Last Updated:Mar 07, 2024

If you encounter issues such as increased service response time or increased costs caused by cross-zone network latency, you can use the zone aware routing feature to ensure that service requests are preferentially processed in the same zone. This decreases network transmission latency, reduces extra costs incurred by cross-zone traffic, and improves the overall efficiency and stability of services. Service Mesh (ASM) allows you to use the zone aware routing feature (also called intra-zone routing) without the need to modify the application code. This topic describes how to use this feature. In the following example, an ingress gateway is used to enable access to an HTTPBin application.

Prerequisites

  • The cluster is added to the ASM instance. For more information, see Add a cluster to an ASM instance.

  • Nodes in the Container Service for Kubernetes (ACK) cluster reside in at least two zones. In this topic, the cn-hongkong-b and cn-hongkong-c zones are used. You can view the region and zone where the Elastic Compute Service (ECS) instance that corresponds to a cluster node resides in the Container Service for Kubernetes (ACK) console. For more information, see Regions and zones.

    Note

    In this example, sleep and helloworld-v1 applications are deployed in cn-hongkong-b, and the helloworld-v2 application is deployed in cn-hongkong-c. Use the zones where your applications reside.

Background information

When a client initiates a request to access a service, the request is preferentially routed to the service on the same node or in the same zone as the client based on the topology information about the region and zone where the client resides. This is how the zone aware routing feature works. Zone aware routing is a load balancing feature. It makes traffic flow in the same zones to reduce service latency.

Step 1: Deploy sample applications

  1. Create a sleep.yaml file that contains the following content:

    Note

    In the following example, the sleep application is deployed in cn-hongkong-b. You can deploy your application in a zone based on your business requirements.

    Expand to view the sleep.yaml file

    # 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. Run the following command to deploy the sleep application in the ACK cluster:

    kubectl apply -f sleep.yaml
  3. Create a helloworld.yaml file that contains the following content.

    Note

    In the following example, the helloworld-v1 application is deployed in cn-hongkong-b and the helloworld-v2 application is deployed in cn-hongkong-c. You can deploy your application in a zone based on your business requirements.

    Expand to view the helloworld.yaml file

    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. Run the following command to deploy the helloworld applications in the ACK cluster:

    kubectl apply -f helloworld.yaml
  5. Run the following command to query the registration information about the service to be accessed:

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

    Expected output:

    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

    The output shows that the two helloworld applications have the same priority priority::0. Therefore, when the sleep client calls the helloworld service, the two helloworld applications have the same routing policies.

Step 2: Enable the zone aware routing feature

Use a destination rule to prioritize the helloworld application in the zone of the client. Enable the zone aware routing feature for the helloworld.default.svc.cluster.local service.

Note

You can enable this feature by configuring the following parameters: consecutive5xxErrors, interval, and baseEjectionTime. In this example, a failover is triggered when the first request fails.

  1. Create a helloworld-failover.yaml file that contains the following content:

    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. Run the following command to view the pod priorities:

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

    Expected output:

    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

    In the output, the priorities of the two helloworld applications are different, which are priority::0 and priority::1, respectively. The output indicates that the zone aware routing feature takes effect when the sleep client calls the helloworld service.

Step 3: Verify the zone aware routing feature

Send a request to call the helloworld service from the sleep application on the client located in the cn-hongkong-b zone. After the zone aware routing feature is enabled, all traffic is routed to the helloworld-v1 application in the same zone with the client. The sleep and helloworld-v1 applications are deployed in cn-hongkong-b, and the helloworld-v2 application is deployed in cn-hongkong-c.

  1. Run the following command multiple times to access the helloworld service:

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

    Expected output:

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

    The output indicates that the returned result is always the helloworld-v1 application.

  2. Scale in the helloworld-v1 application.

    1. Run the following command to scale in the helloworld-v1 application to zero pods and make the application unavailable:

      kubectl scale deploy helloworld-v1 --replicas=0
    2. Wait for a few seconds and run the following command multiple times to access the helloworld service:

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

      Expected output:

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

      The output indicates that the request is routed to the helloworld-v2 application in the cn-hongkong-c zone when the helloworld-v1 application in the same zone as the client becomes unavailable.

  3. Scale out the helloworld-v1 application.

    1. Run the following command to scale out the helloworld-v1 application to one pod and restore the helloworld-v1 application:

      kubectl scale deploy helloworld-v1 --replicas=1
    2. Wait for a few seconds and run the following command multiple times to access the helloworld service:

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

      Expected output:

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

      The output indicates that the returned result is always the helloworld-v1 application.