基于MSE云原生网关实现全链路灰度

在微服务场景中,应用间的调用是随机的。当您部署的Spring Cloud应用或Dubbo应用存在升级版本时,可能会导致无法将具有一定特征的流量路由到应用的目标版本。通过MSE提供的全链路灰度能力,您无需修改业务代码,就可以实现端到端的全链路流量控制。泳道可以将应用的相关版本隔离成一个独立的运行环境。通过设置泳道规则,可以将满足规则的请求流量路由到目标版本的应用。本文介绍如何通过配置MSE云原生网关实现端到端的全链路灰度。

全链路灰度实现流程

image

使用限制

  • 由于全链路灰度功能整合了标签路由功能(此处指的是MSE微服务治理的标签路由,与MSE云原生网关的标签路由无关),因此不推荐已经加入全链路流量控制的应用配置金丝雀发布和标签路由规则。

  • 全链路灰度能力,对于Java应用的限制详见微服务治理支持的Java框架

  • 全链路灰度能力,MSE云原生网关版本需要大于等于2.0.2版本,升级网关版本详见升级MSE云原生网关

场景示例

本文以电商架构中的下单场景为例,介绍从MSE云原生网关到微服务的全链路流控功能。假设应用的架构由MSE云原生网关以及后端的微服务架构(Spring Cloud)组成,后端调用链路有3个:交易中心(A)、商品中心(B)、库存中心(C),可以通过客户端或者HTML来访问后端服务,这些服务之间通过MSE Nacos注册中心实现服务发现。

客户下单后流量从MSE云原生网关进来,调用交易中心(A),交易中心(A)再调用商品中心(B),商品中心(B)调用下游的库存中心(C)。总之,调用链路为:客户>MSE云原生网关>A>B>C。

随着业务不断迭代,新功能需要上线,涉及到应用A和应用C同时发布新版本。在新版本正式上线之前,需要同时对应用A和应用C进行灰度验证,确认无误后方可正式上线。

通过MSE云原生网关和MSE微服务治理提供的全链路灰度能力,您可以端到端构建从网关到多个后端服务的全链路灰度,控制具有一定特征的灰度流量始终路由到应用对应的灰度环境,满足您同时灰度验证多个服务的诉求。此外,在应用无目标灰度版本时,自动容灾到正式环境中。

使用场景

名词解释

  • MSE云原生网关:MSE云原生网关是兼容K8s Ingress标准的下一代网关产品,支持ACK容器和Nacos等多种服务发现方式,支持多种认证登录方式快速构建安全防线。更多信息,请参见云原生网关概述

  • 泳道:为相同版本应用定义的一套隔离环境。只有满足了流控路由规则的请求流量才会路由到对应泳道里的打标应用。一个应用可以属于多个泳道,一个泳道可以包含多个应用,应用和泳道是多对多的关系。

  • 泳道组:泳道的集合。泳道组的作用主要是为了区分不同团队或不同场景。

  • 基线环境:未打标的应用属于基线环境,是其他环境的兜底环境。

准备工作

创建Kubernetes集群

具体操作,请参见创建ACK专有集群创建ACK托管集群

开启MSE微服务治理

重要

请确保MSE Java 探针的版本3.2.3及以上,否则会影响业务运行。

  1. MSE微服务治理开通页面,开通微服务治理专业版。

  2. 将ACK微服务应用接入MSE治理中心,您可以选择您需要的方式实现应用接入。更多信息,请参见ACK微服务应用接入MSE治理中心

创建MSE云原生网关

具体操作,请参见创建MSE云原生网关

为云原生网关关联服务来源

具体操作,请参见创建服务来源

说明
  • 基于MSE云原生网关的全链路灰度目前暂只支持容器服务和MSE Nacos两种来源。

  • MSE云原生网关与容器服务的Kubernetes集群/MSE Nacos需要处于同一VPC。

步骤一:搭建业务应用的基线环境

步骤1:部署后端业务应用的基线版本

  1. 登录容器服务控制台
  2. 在左侧导航栏,单击集群,然后单击目标集群名称。
  3. 在左侧导航栏,选择工作负载 > 无状态
  4. 在页面上方,选择集群的命名空间,然后单击右上角的使用YAML创建资源
  5. 部署基线应用。

    服务来源为MSE Nacos

    复制如下YAML文件内容,部署A、B、C三个应用的基线版本。

    说明

    代码中的{nacos server address}需要替换成您创建的MSE Nacos的内网域名,同时需要去掉大括号{}

    展开查看YAML文件

    # 应用A的基线版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-a
      namespace: default
    spec:
      selector:
        matchLabels:
          app: spring-cloud-a
      template:
        metadata:
          labels:
            app: spring-cloud-a
            msePilotCreateAppName: spring-cloud-a
            msePilotAutoEnable: 'on'
        spec:
          containers:
          - name: spring-cloud-a
            image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-a:3.0.1
            imagePullPolicy: Always
            ports:
              - containerPort: 20001
            livenessProbe:
              tcpSocket:
                port: 20001
              initialDelaySeconds: 30
              periodSeconds: 60
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: {nacos server address}
            - name: dubbo.registry.address
              value: 'nacos://{nacos server address}:8848'
    ---
    # 应用B的基线版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-b
      namespace: default
    spec:
      selector:
        matchLabels:
          app: spring-cloud-b
      template:
        metadata:
          labels:
            app: spring-cloud-b
            msePilotCreateAppName: spring-cloud-b
            msePilotAutoEnable: 'on'
        spec:
          containers:
          - name: spring-cloud-b
            image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-b:3.0.1
            imagePullPolicy: Always
            ports:
              - containerPort: 20002
            livenessProbe:
              tcpSocket:
                port: 20002
              initialDelaySeconds: 30
              periodSeconds: 60
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: {nacos server address}
            - name: dubbo.registry.address
              value: 'nacos://{nacos server address}:8848'
    ---
    # 应用C的基线版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-c
      namespace: default
    spec:
      selector:
        matchLabels:
          app: spring-cloud-c
      template:
        metadata:
          labels:
            app: spring-cloud-c
            msePilotCreateAppName: spring-cloud-c
            msePilotAutoEnable: 'on'
        spec:
          containers:
          - name: spring-cloud-c
            image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-c:3.0.1
            imagePullPolicy: Always
            ports:
              - containerPort: 20003
            livenessProbe:
              tcpSocket:
                port: 20003
              initialDelaySeconds: 30
              periodSeconds: 60
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: {nacos server address}
            - name: dubbo.registry.address
              value: 'nacos://{nacos server address}:8848'

    服务来源为容器服务

    1. 复制如下YAML文件,部署Nacos,模拟自建服务注册中心的场景。

      展开查看YAML文件

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: nacos-server
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: nacos-server
        template:
          metadata:
            labels:
              msePilotAutoEnable: "off"
              app: nacos-server
          spec:
            containers:
              - name: nacos-server
                image: 'registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/nacos-server:v2.1.2'
                env:
                  - name: MODE
                    value: standalone
                  - name: JVM_XMS
                    value: 512M
                  - name: JVM_XMX
                    value: 512M
                  - name: JVM_XMN
                    value: 256M
                imagePullPolicy: Always
                livenessProbe:
                  failureThreshold: 3
                  initialDelaySeconds: 15
                  periodSeconds: 10
                  successThreshold: 1
                  tcpSocket:
                    port: 8848
                  timeoutSeconds: 3
                readinessProbe:
                  failureThreshold: 5
                  initialDelaySeconds: 15
                  periodSeconds: 15
                  successThreshold: 1
                  tcpSocket:
                    port: 8848
                  timeoutSeconds: 3
                resources:
                  requests:
                    cpu: '1'
                    memory: 2Gi
            dnsPolicy: ClusterFirst
            restartPolicy: Always
      
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: nacos-server
      spec:
        type: ClusterIP
        ports:
          - name: nacos-server-8848-8848
            port: 8848
            protocol: TCP
            targetPort: 8848
          - name: nacos-server-9848-9848
            port: 9848
            protocol: TCP
            targetPort: 9848
        selector:
          app: nacos-server
    2. 复制如下YAML文件,部署A、B、C三个应用的基线版本。

      展开查看YAML文件

      # 应用A的基线版本
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: spring-cloud-a
        namespace: default
      spec:
        selector:
          matchLabels:
            app: spring-cloud-a
        template:
          metadata:
            labels:
              app: spring-cloud-a
              msePilotCreateAppName: spring-cloud-a
              msePilotAutoEnable: 'on'
          spec:
            containers:
            - name: spring-cloud-a
              image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-a:3.0.1
              imagePullPolicy: Always
              ports:
                - containerPort: 20001
              livenessProbe:
                tcpSocket:
                  port: 20001
                initialDelaySeconds: 30
                periodSeconds: 60
              # 通过Nacos的Service访问自建Nacos
              env:
              - name: spring.cloud.nacos.discovery.server-addr
                value: nacos-server
              - name: dubbo.registry.address
                value: 'nacos://nacos-server:8848'
      ---
      # 应用B的基线版本
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: spring-cloud-b
        namespace: default
      spec:
        selector:
          matchLabels:
            app: spring-cloud-b
        template:
          metadata:
            labels:
              app: spring-cloud-b
              msePilotCreateAppName: spring-cloud-b
              msePilotAutoEnable: 'on'
          spec:
            containers:
            - name: spring-cloud-b
              image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-b:3.0.1
              imagePullPolicy: Always
              ports:
                - containerPort: 20002
              livenessProbe:
                tcpSocket:
                  port: 20002
                initialDelaySeconds: 30
                periodSeconds: 60
              # 通过Nacos的Service访问自建Nacos
              env:
              - name: spring.cloud.nacos.discovery.server-addr
                value: nacos-server
              - name: dubbo.registry.address
                value: 'nacos://nacos-server:8848'
      ---
      # 应用C的基线版本
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: spring-cloud-c
        namespace: default
      spec:
        selector:
          matchLabels:
            app: spring-cloud-c
        template:
          metadata:
            labels:
              app: spring-cloud-c
              msePilotCreateAppName: spring-cloud-c
              msePilotAutoEnable: 'on'
          spec:
            containers:
            - name: spring-cloud-c
              image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-c:3.0.1
              imagePullPolicy: Always
              ports:
                - containerPort: 20003
              livenessProbe:
                tcpSocket:
                  port: 20003
                initialDelaySeconds: 30
                periodSeconds: 60
              # 通过Nacos的Service访问自建Nacos
              env:
              - name: spring.cloud.nacos.discovery.server-addr
                value: nacos-server
              - name: dubbo.registry.address
                value: 'nacos://nacos-server:8848'
    3. 复制如下YAML文件,为入口应用A创建Service。

      展开查看YAML文件

      # 暴露应用A
      apiVersion: v1
      kind: Service
      metadata:
        name: sc-a
        namespace: default
      spec:
        ports:
          - port: 20001
            protocol: TCP
            targetPort: 20001
        selector:
          app: spring-cloud-a
        type: ClusterIP

步骤2:通过MSE云原生网关暴露应用A

情况一:新服务

如果您未在云原生网关上添加过应用A,可以通过如下操作暴露应用A。

  1. 登录MSE管理控制台。选择云原生网关 > 网关列表,单击已创建的云原生网关实例。在左侧导航栏的路由管理页面,选择服务页签,单击创建服务。具体操作,请参见创建服务

    • 来源为容器服务

      • 服务来源选择容器服务

      • 命名空间选择default。

      • 服务列表选择sc-a。

    • 来源为MSE Nacos

      • 服务来源:选择MSE Nacos

      • 命名空间:选择public。

      • 服务列表:选择sc-A

  2. 路由管理页面,选择路由页签。单击创建路由,为服务sc-a/sc-A创建路由完成对外暴露。具体操作,请参见创建路由

    配置项

    描述

    路径(Path)

    选择匹配条件为前缀是,路径为/a。

    路由指向

    选择单服务

    后端服务

    选择 sc-A

情况二:线上已有服务

如果您的实际场景是针对已导入的服务,可通过如下操作暴露应用A。

登录MSE管理控制台。选择云原生网关 > 网关列表,选择已创建的云原生网关实例。在左侧导航栏路由管理页面,选择路由页签。编辑已有的路由,以便暴露服务。

配置项

描述

路径(Path)

选择匹配条件为前缀是,路径为/a。

路由指向

选择单服务

后端服务

选择 sc-A

步骤3:测试基线版本流量

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。

  3. 在左侧导航栏,单击基本概览

  4. 网关入口页签,查看SLB的入口地址

  5. 使用curl命令,测试基线版本流量,发现流量经过了A、B和C的基线版本。如下所示:

    # 测试命令
    curl x.x.1.1/a
    
    # 测试结果
    A[10.0.3.178][config=base] -> B[10.0.3.195] -> C[10.0.3.201]

    如测试结果所示,B和C输出结果的应用名后面没有版本,则代表访问对应应用的基线版本。

步骤二:搭建业务应用的灰度环境

如果业务应用要发布新功能,新功能要求应用A和应用C同时发版,这时就需要借助全链路灰度来同时验证不同应用的灰度版本。

步骤1:部署后端业务应用的灰度版本

  1. 登录容器服务控制台
  2. 在左侧导航栏,单击集群,然后单击目标集群名称。
  3. 在左侧导航栏,选择工作负载 > 无状态
  4. 在页面上方,选择集群的命名空间,然后单击右上角的使用YAML创建资源
  5. 复制以下YAML文件内容,部署A、C两个应用的灰度版本。

    服务来源为MSE Nacos

    说明

    代码中的{nacos server address}需要替换成您创建的MSE Nacos的内网域名,同时需要去掉大括号{}

    展开查看YAML文件

    # 应用A的灰度版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-a-gray
      namespace: default
    spec:
      selector:
        matchLabels:
          app: spring-cloud-a-gray
      template:
        metadata:
          labels:
            alicloud.service.tag: gray
            app: spring-cloud-a-gray
            msePilotCreateAppName: spring-cloud-a
            msePilotAutoEnable: 'on'
        spec:
          containers:
          - name: spring-cloud-a
            image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-a:3.0.1
            imagePullPolicy: Always
            ports:
              - containerPort: 20001
            livenessProbe:
              tcpSocket:
                port: 20001
              initialDelaySeconds: 30
              periodSeconds: 60
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: {nacos server address}
            - name: dubbo.registry.address
              value: 'nacos://{nacos server address}:8848'
    ---
    # 应用C的灰度版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-c-gray
      namespace: default
    spec:
      selector:
        matchLabels:
          app: spring-cloud-c-gray
      template:
        metadata:
          labels:
            alicloud.service.tag: gray
            app: spring-cloud-c-gray
            msePilotCreateAppName: spring-cloud-c
            msePilotAutoEnable: 'on'
        spec:
          containers:
          - name: spring-cloud-c
            image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-c:3.0.1
            imagePullPolicy: Always
            ports:
              - containerPort: 20003
            livenessProbe:
              tcpSocket:
                port: 20003
              initialDelaySeconds: 30
              periodSeconds: 60
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: {nacos server address}
            - name: dubbo.registry.address
              value: 'nacos://{nacos server address}:8848'

    服务来源为容器服务

    展开查看YAML文件

    # 应用A的灰度版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-a-gray
      namespace: default
    spec:
      selector:
        matchLabels:
          app: spring-cloud-a
      template:
        metadata:
          labels:
            alicloud.service.tag: gray
            app: spring-cloud-a
            msePilotCreateAppName: spring-cloud-a
            msePilotAutoEnable: 'on'
        spec:
          containers:
          - name: spring-cloud-a
            image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-a:3.0.1
            imagePullPolicy: Always
            ports:
              - containerPort: 20001
            livenessProbe:
              tcpSocket:
                port: 20001
              initialDelaySeconds: 30
              periodSeconds: 60
            # 通过Nacos的Service访问自建Nacos
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: nacos-server
            - name: dubbo.registry.address
              value: 'nacos://nacos-server:8848'
    
    ---
    # 应用C的灰度版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-c-gray
      namespace: default
    spec:
      selector:
        matchLabels:
          app: spring-cloud-c
      template:
        metadata:
          labels:
            alicloud.service.tag: gray
            app: spring-cloud-c
            msePilotCreateAppName: spring-cloud-c
            msePilotAutoEnable: 'on'
        spec:
          containers:
          - name: spring-cloud-c
            image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-c:3.0.1
            imagePullPolicy: Always
            ports:
              - containerPort: 20003
            livenessProbe:
              tcpSocket:
                port: 20003
              initialDelaySeconds: 30
              periodSeconds: 60
            # 通过Nacos的Service访问自建Nacos
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: nacos-server
            - name: dubbo.registry.address
              value: 'nacos://nacos-server:8848'

步骤2:创建灰度环境泳道组

  1. 登录MSE治理中心控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择治理中心 > 全链路灰度

  3. 如果您选择的微服务命名空间内没有创建过泳道组,则单击创建泳道组及泳道。如果您选择的微服务命名空间内已经创建过泳道组,则单击+创建泳道组

  4. 创建泳道组面板,设置如下相关配置,然后单击确定

    配置项

    说明

    泳道组名称

    自定义泳道组的名称。

    入口类型

    选择MSE 云原生网关

    入口网关

    选择目标云原生网关。

    泳道组涉及应用

    选择spring-cloud-aspring-cloud-bspring-cloud-c

    创建泳道组.png

    泳道组创建完成后,在全链路灰度页面的泳道组区域,可以查看您创建的泳道组。如需变更泳道组信息,单击编辑图标,可在页面自行修改相关信息。

步骤3:创建灰度环境泳道

说明
  • 使用全链路灰度功能时,需要您给灰度应用添加一个特殊的 tag 标记,以便将这些节点和其他节点区分开来。容器环境下需要您在spec.template.metadata.labels下增加alicloud.service.tag: ${tag}信息;在ECS环境下需要添加Java启动参数-Dalicloud.service.tag=${tag}

  • 以云原生网关作为全链路灰度入口时,MSE支持两种泳道灰度模式。

    • 按请求内容灰度:当请求内容可以用于灰度识别时,建议采用此种灰度模式。如果不可以,也强烈建议您通过系统改造增加此类灰度标识,以便获得更好的灰度效果。比如,可以保持灰度请求前后的一致性。

    • 按比例路由灰度:当请求内容无法用于灰度识别且遗留系统也无法进行改造时,可以采用此种退化的灰度模式。该模式有一定弊端,可能导致同一来源的请求进入不同泳道,而造成灰度请求前后行为的不一致。

  • 泳道路由模式在一个泳道组中需要保持一致。您只有在创建泳道组中第一条泳道时可以调整泳道路由的灰度模式。

  1. 全链路灰度页面底部,如果您选择的微服务命名空间内没有创建过泳道,则单击点击创建第一个分流泳道。如果您选择的微服务命名空间内已经创建过泳道,则单击+创建泳道

  2. 创建泳道面板,设置流控泳道相关配置,然后单击确定

    创建按请求内容路由的泳道

    配置项

    说明

    配置节点标签

    需要您给灰度应用节点打上标签,以便与正常节点做区分。

    填写泳道信息

    泳道名称:输入便于理解和识别的泳道名称。

    泳道标签:该泳道内的匹配的流量去往的目标标签。

    确认匹配关系:检查您配置了该标签的应用节点数是否符合预期。

    泳道状态:选择开启。

    配置路由和灰度规则

    设置流量进入该泳道的规则。

    • 选择路由:选择在步骤一创建的基线路由名称,基线路由为单服务类型的路由。

    • 灰度模式:选择按内容灰度

    • 灰度条件:选择以下条件同时满足

      本示例灰度条件配置如下:

      • 参数类型:Header。

      • 参数:canary。

      • 条件:==。

      • :gray。

    泳道路由模式说明

    灰度条件

    效果

    以下条件同时满足

    需要所有条件内容满足的流量才会去往对应的泳道。

    以下条件任意满足

    满足如下任意一个条件内容的流量就会去往对应的泳道。

    条件内容说明

    条件

    描述

    全链路灰度配置示例

    云原生网关请求示例

    ==

    精确匹配,流量值与条件值需要完全相等。

    image.png

    image.png

    !=

    不等匹配,流量值与条件值不相等时满足条件。

    image.png

    image.png

    in

    包含匹配,流量值需要在指定的列表中时满足条件。

    image.png

    image.png

    百分比

    百分比匹配,原理:满足`hash(get(key)) % 100 < value` 成立时满足条件。

    image.png

    image.png

    正则匹配

    正则表达式匹配,按照正则表达式规则匹配时满足条件。

    image.png

    image.png

    前缀匹配

    前缀匹配,指定值是实际值的前缀时满足条件。

    image.png

    image.png

    创建按比例路由的泳道

    说明

    创建按比例路由的泳道,需要ack-onepilot版本为3.0.18及以上,且探针版本为3.2.3及以上。

    配置项

    说明

    配置节点标签

    需要您手工给您的灰度应用节点打上标签,以便与正常节点做区分。

    填写泳道信息

    泳道名称:输入便于理解和识别的泳道名称。

    泳道标签:该泳道内的匹配的流量去往的目标标签。

    确认匹配关系:检查您配置了该标签的应用节点数是否符合预期。

    泳道状态:选择开启。

    配置路由和灰度规则

    设置流量进入该泳道的规则。

    • 选择路由:选择在步骤一创建的基线路由名称。

    • 灰度模式:选择按比例路由

    • 流量比例:30%。

    说明

    您还可以为每条网关基线路由分别设置不同的流量比例,开启该功能时,您需要注意该网关基线路由当前在所有泳道组中配置的流量比例总和不应超过100%。

完成泳道创建后,在全链路灰度流量分配区域,可以查看泳道详情,还可以进行如下操作。

  • 操作列,选择开启,创建的泳道将会生效,即流量会按照泳道方式进行流转,满足规则的流量会优先流向标记有当前泳道对应标签的应用版本,如果没有对应标签的应用版本则流向未打标的应用版本。

  • 操作列,选择关闭,关闭创建的泳道,即该应用往后的流量会流向未打标的应用版本。

  • 单击图标图标,可以查看该泳道的流量比例。

  • 单击应用状态图标图标,可以设置该泳道上应用的状态。

步骤4:测试灰度版本流量

测试按请求内容路由的泳道

使用curl命令测试灰度流量,如测试结果所示,流量经过了A、C的灰度环境,由于B没有gray环境,所以流量自动容灾到基线版本。

# 测试命令
curl -H "canary: gray" x.x.x.x/a

# 测试结果
Agray[10.0.3.177][config=base] -> B[10.0.3.195] -> Cgray[10.0.3.180]

测试按比例路由的泳道

可以通过如下Python脚本测试按比例路由的分流情况(需要安装requests包),并将“x.x.x.x”替换为云原生网关的入口SLB地址。

展开查看Python脚本

# pip3 install requests
# python3 traffic.py
import requests


TOTAL_REQUEST = 100
ENTRY_URL = 'http://x.x.x.x/a'

def parse_tag(text:str):
    '''
    A[10.0.23.64][config=base] -> B[10.0.23.65] -> C[10.0.23.61]
    Agray[10.0.23.64][config=base] -> B[10.0.23.65] -> Cgray[10.0.23.61]
    Ablue[10.0.23.64][config=base] -> B[10.0.23.65] -> Cblue[10.0.23.61]
    '''
    print(text)
    app_parts = text.split(' -> ')
    # tag_app: C[10.0.23.61] / Cgray[10.0.23.61]
    tag_app = app_parts[-1]
    
    splits = tag_app.split('[')
    
    # tag_part: C / Cgray
    tag_part = splits[0]
    tag = tag_part[1:]
    return tag if len(tag) > 0 else 'base'

def get_tag(url:str):
    resp = requests.get(url)
    resp.encoding = resp.apparent_encoding
    return parse_tag(resp.text)

def cal_tag_count(url:str, total_request:int):
    count_map = {}
    for i in range(total_request):
        tag = get_tag(url)
        if tag not in count_map:
            count_map[tag] = 1
        else:
            count_map[tag] += 1

    print()
    print('Total Request:', total_request)
    print('Traffic Distribution:', count_map)


if __name__ == '__main__':
    cal_tag_count(ENTRY_URL, TOTAL_REQUEST)

从结果可以看到,约有30%比例的流量去往了灰度环境。

image

(可选)步骤三:可观测

若应用出现异常,您可以通过MSE提供的可观测能力查看异常数据,帮助您快速定位问题。

云原生网关可观测

在MSE云原生网关的路由管理页面,选择服务页签。单击目标服务,在监控区域查看服务的流量情况。

基础监控

微服务治理可观测

在MSE微服务治理的全链路灰度页面,单击目标应用,在应用 QPS 监控区域,可查看对应泳道基线版本和灰度版本的流量情况。

应用监控

  • 总QPS:该应用总的QPS。

  • 异常QPS:该应用出错的请求数。

  • GrayQPS:该应用gray版本的QPS。