使用ASM回退机制

当服务调用执行未成功时,回退机制提供替代的另外执行路径。当某个微服务发生故障或无法使用时,回退机制会调用一个备用的服务来处理请求,以确保整个系统的稳定性和可用性。例如,当一个服务端点不可用时,可以使用回退机制将请求转发到一个备用的服务版本,确保客户端请求能够继续正常运行,而不会出现错误或中断。ASM支持在VirtualService中定义fallback参数以支持请求服务失败时的回退机制。本文介绍如何使用ASM回退机制。

前提条件

  • 已创建ASM企业版或旗舰版实例,且版本为1.17.2.22及以上。具体操作,请参见创建ASM实例

    说明

    若ASM实例版本为1.17以下的版本,请将实例升级至1.17.2.22及以上版本,或提交工单获取技术支持。关于升级的具体操作,请参见升级ASM实例

  • 已添加ACK集群到ASM实例。具体操作,请参见添加集群到ASM实例

  • 已部署Bookinfo示例。具体操作,请参见在ASM实例关联的集群中部署应用

  • 数据面Sidecar版本需为1.17及以上。

    说明

    您可以通过ASM控制台网格状态页面,查看每个业务Pod对应的Sidecar版本。更多信息,请参见升级管理

配置说明

本文以Bookinfo示例中的reviews服务为例。当productpage服务访问reivews服务的三个版本v1、v2、v3时,如果v3版本不可用,将执行回退机制降级访问v2版本,并且不返回503失败信息。

您可以单击配置文件,直接下载本文使用的相关YAML文件。

步骤一:访问Bookinfo示例

  1. 使用以下内容,创建reviews.yaml文件,声明reviews服务的v1、v2、v3三个版本。

    apiVersion: networking.istio.io/v1alpha3
    kind: DestinationRule
    metadata:
      name: reviews
    spec:
      host: reviews
      subsets:
      - name: v1
        labels:
          version: v1
      - name: v2
        labels:
          version: v2
      - name: v3
        labels:
          version: v3
  2. 在ASM实例对应的KubeConfig环境下,执行以下命令,部署DestinationRule。

    kubectl apply -f reviews.yaml
  3. 任选以下方式,获取网关的IP。

    • 方式一:通过以下命令获取。

    kubectl get svc -n istio-system  istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
    • 方式二:通过ASM控制台的入口网关页面获取网关IP。具体操作,请参见获取ASM网关地址

  4. 在浏览器中访问http://${YourGatewayIp}/productpage

    ${YourGatewayIp}为上一步获取的网关IP。您可以通过Reviews served by的值或星星来判断版本。v1版本没有星星,v2版本为黑色星星,v3版本为红色星星。

    例如,下图reviews-v2表示v2版本,星星为黑色。v2版本示例..png

    不断刷新页面,您可以看到请求reviews时,负载均衡到reviews的v1、v2、v3三个版本。

步骤二:定义访问reviews的路由和回退规则

  1. 使用以下内容,创建reviews-route-fallback-sample1.yaml文件。

    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: reviews-route
      namespace: default
    spec:
      hosts:
        - reviews
      http:
        - route:
            - destination:
                host: reviews
                subset: v3
              fallback:
                target:
                  host: reviews
                  subset: v2
    
  2. 在ASM实例对应的KubeConfig环境下,执行以下命令,部署访问reviews的路由和回退规则。

    kubectl apply -f reviews-route-fallback-sample1.yaml
  3. 在浏览器中访问http://${YourGatewayIp}/productpage,并不断刷新页面。

    可以看到请求一直在reviews的v3版本上。v3版本..png

  4. 执行以下命令,人为模拟reviews-v3版本故障,将reviews-v3的副本实例数修改为0。

    kubectl scale deployment reviews-v3 --replicas=0
  5. 在浏览器中访问http://${YourGatewayIp}/productpage,并不断刷新页面。

    可以看到请求正确回退到reviews的v2的版本上。您可以通过在自定义访问日志格式中添加Fallback相关字段,然后查看日志,判断是否进行了回退。

    展开查看是否进行了回退

    1. 在自定义访问日志格式中添加如下字段。具体操作,请参见自定义数据面访问日志内容

      字段

      取值

      说明

      fallback_path

      %DYNAMIC_METADATA(com.aliyun.fallback:fallback-path)%

      回退的具体路径。例如A:B表示A回退到B;A:B:C表示A回退到B,因为B也不健康,所以回退到C。

      fallback_final_cluster_name

      %DYNAMIC_METADATA(com.aliyun.fallback:final-cluster)%

      若回退,则回退到对应的目标集群。例如当service1|v1不存在时,回退到service|base。

      fallback_result

      %DYNAMIC_METADATA(com.aliyun.fallback:fallback-result)%

      回退的结果,若失败则发送给原路由的集群。

      自定义日志格式..png

    2. 查看produpage-v1的istio-proxy的日志。

      当reviews-v3回退到reviews-v2时,日志示例如下:

      {
          "authority":"reviews:9080",
          "authority_for":"reviews:9080",
          "bytes_received":"0",
          "bytes_sent":"442",
          "downstream_local_address":"192.168.255.46:9080",
          "downstream_remote_address":"172.16.0.252:57238",
          "duration":"10",
          "fallback_path":"outbound|9080|v3|reviews.default.svc.cluster.local:outbound|9080|v2|reviews.default.svc.cluster.local",
          "fallback_final_cluster_name":"outbound|9080|v2|reviews.default.svc.cluster.local",
          "fallback_result":"fallback successful",
          "istio_policy_status":"-",
          "method":"GET",
          "path":"/reviews/0",
          "protocol":"HTTP/1.1",
          "request_id":"15b2dffc-5f3f-4060-b9fa-898eab08****",
          "requested_server_name":"-",
          "response_code":"200",
          "response_flags":"-",
          "route_name":"-",
          "start_time":"2023-05-30T07:02:26.990Z",
          "trace_id":"18b3aed8af41****",
          "upstream_cluster":"outbound|9080|v2|reviews.default.svc.cluster.local",
          "upstream_host":"172.16.0.11:9080",
          "upstream_local_address":"172.16.0.252:44448",
          "upstream_service_time":"9",
          "upstream_transport_failure_reason":"-",
          "user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.X.X Safari/537.36",
          "x_forwarded_for":"-"
      }

      您可以在日志中看到如下新增的日志字段。

      "fallback_path":"outbound|9080|v3|reviews.default.svc.cluster.local:outbound|9080|v2|reviews.default.svc.cluster.local"
      "fallback_final_cluster_name":"outbound|9080|v2|reviews.default.svc.cluster.local"
      "fallback_result":"fallback successful"

      通过日志可以看到原本的路由目标是v3,因为v3下实例不可用,请求回退到v2版本。

步骤三:在带有权重的路由下配置回退规则

  1. 执行以下命令,将reviews-v3版本置为可用状态。

    kubectl scale deployment reviews-v3 --replicas=1
  2. 使用如下内容,创建reviews-route-fallback-sample2.yaml文件,修改reviews-route的定义。

    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: reviews-route
      namespace: default
    spec:
      hosts:
        - reviews 
      http:
        - route:
            - destination:
                host: reviews 
                subset: v3
              fallback:
                target:
                  host: reviews 
                  subset: v2
              weight: 50
            - destination:
                host: reviews 
                subset: v2
              fallback:
                target:
                  host: reviews 
                  subset: v1
              weight: 50
          retries:
            attempts: 0
  3. 执行以下命令,部署reviews新的路由和回退规则。

    kubectl apply -f reviews-route-fallback-sample1.yaml
  4. 在浏览器中访问http://${YourGatewayIp}/productpage,并不断刷新页面。

    可以看请求按50:50的比例落在reviews的v2和v3版本。为了让显示效果更明显,本示例关闭了重试。

  5. 执行以下命令,将v3的副本实例个数调整为0,验证v3的回退规则是否符合预期。

    kubectl scale deployment reviews-v3 --replicas=0

    不断刷新productpage页面,可以看到请求一直reviews的v2版本下,符合预期。

  6. 执行以下命令,将v2的副本实例数调整为0。

    kubectl scale deployment reviews-v2 --replicas=0

    不断刷新productpage页面,可以看到类似如下页面,productpage访问reviews失败。该页面出现的概率为50%,另外50%的概率请求到了v2版本。因为v2版本不健康,实际请求回退到v1版本。productpage页面..png

  7. 执行以下命令,查看日志。

    kubectl logs -f  deployment/productpage-v1  -c istio-proxy --tail=10

    预期输出:

    {
        "authority":"reviews:9080",
        "authority_for":"reviews:9080",
        "bytes_received":"0",
        "bytes_sent":"19",
        "downstream_local_address":"192.168.255.46:9080",
        "downstream_remote_address":"172.16.0.252:47738",
        "duration":"0",
        "fallback_path":"outbound|9080|v3|reviews.default.svc.cluster.local:outbound|9080|v2|reviews.default.svc.cluster.local",
        "fallback_final_cluster_name":"-",
        "fallback_result":"fallback cluster is unhealthy",
        "istio_policy_status":"-",
        "method":"GET",
        "path":"/reviews/0",
        "protocol":"HTTP/1.1",
        "request_id":"b207a764-b6d7-4ef8-bc71-59f264c3****",
        "requested_server_name":"-",
        "response_code":"503",
        "response_flags":"UH",
        "route_name":"-",
        "start_time":"2023-05-30T07:32:08.999Z",
        "trace_id":"a40c32a7b2cf****",
        "upstream_cluster":"outbound|9080|v3|reviews.default.svc.cluster.local",
        "upstream_host":"-",
        "upstream_local_address":"-",
        "upstream_service_time":"-",
        "upstream_transport_failure_reason":"-",
        "user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.X.X Safari/537.36",
        "x_forwarded_for":"-"
    }

    可以看到productpage-v1下有类似如上503日志。基于reviews-route带权重的路由配置,productpage会有50%的概率请求v3版本的reviews。由于v3版本不可用,Sidecar(istio-proxy) 基于回退规则,尝试从v3回退到v2版本。由于v2版本不健康,请求发往了v3版本。您可以通过字段"upstream_cluster":"outbound|9080|v3|reviews.default.svc.cluster.local"进行确认。