全部产品
Search
文档中心

服务网格 ASM:基于网格层跨集群使用流量镜像

更新时间:Nov 15, 2023

流量镜像功能可以将生产的流量镜像拷贝到测试集群或者新的测试版本中,在不影响实际生产环境的情况下,测试具有实际生产流量的服务,帮助您减低版本变更的风险。本文介绍什么是流量镜像,以及如何基于网格层跨集群使用流量镜像。

什么是流量镜像?

微服务能够帮助用户快速地开发和部署应用,但版本变更中也存在一定风险。服务网格ASM提供流量镜像(Traffic Mirroring)的功能,也称影子流量(Traffic Shadowing)。该功能将实时流量的副本发送到镜像服务,而镜像流量发生在主服务的关键请求路径之外。当流量被镜像时,请求将通过其主机或授权报头发送到镜像服务添加“–shadow”标记,用以区分流量从何处被镜像到何处。流量镜像功能可以将生产的流量镜像拷贝到测试集群或者新的测试版本中,在引导实时流量之前进行测试,有效地降低版本变更的风险。

功能优势

优势

说明

测试环境更加真实,版本部署风险更低。

流量镜像功能可以将生产的流量镜像拷贝到测试集群或者新的测试版本中,利用实时生产用例和流量进行测试,使得测试服务环境更加真实,测试结果更加准确,帮助您降低生产环境部署的风险。

不影响实际生产环境。

  • 当流量镜像到不同的服务时,会发生在请求的关键路径之外。流量镜像产生的任何问题都不会影响生产环境。

  • 忽略对任何镜像流量的响应,流量被视为“即发即忘”。镜像实例发回的任何响应都将被忽略,不会干扰到正常的生产流量的响应。

适用场景

流量镜像可以在不影响最终客户端的情况下,测试具有实际生产流量的服务。您可以使用流量镜像功能,验证新版本是否能够以相同的方式处理真正的各种传入请求、在同一服务的两个版本之间进行比较基准测试等。

下面介绍几种典型的应用场景,帮助您发挥流量镜像的优势。

应用场景

说明

线上流量模拟和测试

测试集群的测试可以使用生产实例真实流量,不会影响正常生产的关键路径。例如,用新系统替换老旧系统或者系统经历大规模改造时,您可以将线上流量导入新系统,进行试运行;对于一些实验性的架构调整,您也可以通过线上流量进行模拟测试。

新版本校验

您可以实时对比生产流量和镜像流量的输出结果。由于是全样本的模拟,影子流量可以应用于新服务的预上线演练。传统的手工测试本身是一种样本化的行为,通过导入真实流量形态,可以完整地模拟线上的所有情况,例如异常的特殊字符、带恶意攻击的Token等,帮助您探测预发布服务最真实的处理能力和对异常的处理能力。

隔离测试数据库

与数据处理相关的业务,可以使用空的数据存储并加载测试数据。针对该数据进行镜像流量操作,实现测试数据的隔离。

线上问题排查和临时的数据采集

对于一些线上突发性问题,在线下流量总是无法复现,此时您可以临时开启一个分支服务,导入影子流量进行调试和排查。采用此方式,不影响线上服务。

日志行为采集

对于推荐系统和算法来说,样本和数据非常核心。传统的自动化测试在算法类的应用面临的最大挑战是无法构建真实环境的用户行为数据。通过影子流量可以将用户行为以日志的形式保存起来,既可以为推荐系统和算法模型构建模拟测试样本数据,也可以作为后续大数据分析用户画像的数据来源再应用到推荐服务中。

启用流量镜像示例代码

使用Istio启用流量镜像的YAML示例如下。YAML示例中,VirtualService将100%的流量路由到v1子集,同时将相同的流量镜像到v1-mirroring子集。发送给v1子集的相同请求将被复制并触发v1-mirroring子集。

当v1-mirroring将一些请求发送到应用程序的v1版本时,您可以查看应用程序的日志。调用应用程序时,获得的响应来自v1子集。您还可以看到请求镜像到v1-mirroring子集。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-traffic-mirroring
spec:
  hosts:
    - myapp
  http:
    - route:
        - destination:
            host: myapp.default.svc.cluster.local
            port:
              number: 8000
            subset: v1
          weight: 100
      mirror:
        host: myapp.default.svc.cluster.local
        port:
          number: 8000
        subset: v1-mirroring

跨集群使用流量镜像流程介绍

基于网格层使用流量镜像一般多用于为预发布环境导入线上真实流量的场景,因此在跨集群中比较常见。本文以生产环境的集群(clusterA)和测试集群(clusterB)为例,主体请求在生产环境的集群clusterA上,由它的网关将流量镜像拷贝到集群clusterB中。基于集群内服务层使用流量镜像

步骤一:在测试集群中配置并启动示例应用服务

  1. 使用以下内容,创建httpbin.yaml文件。

    展开查看httpbin.yaml

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: httpbin
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: httpbin
      labels:
        app: httpbin
        service: httpbin
    spec:
      ports:
      - name: http
        port: 8000
        targetPort: 80
      selector:
        app: httpbin
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin-v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: httpbin
          version: v1
      template:
        metadata:
          labels:
            app: httpbin
            version: v1
        spec:
          serviceAccountName: httpbin
          containers:
          - image: docker.io/kennethreitz/httpbin
            imagePullPolicy: IfNotPresent
            name: httpbin
            ports:
            - containerPort: 80
    ---
  2. 执行以下命令,部署v1版本的httpbin服务。

    kubectl apply -f httpbin.yaml

步骤二:在测试集群中配置网关路由规则

  1. 使用以下内容,创建httpbin-gateway.yaml文件。

    展开查看httpbin-gateway.yaml

    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: httpbin-gateway
    spec:
      selector:
        istio: ingressgateway
      servers:
      - port:
          number: 80
          name: http
          protocol: HTTP
        hosts:
        - "*"
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: httpbin
    spec:
      hosts:
      - "*"
      gateways:
      - httpbin-gateway
      http:
      - match:
        - uri:
            prefix: /headers
        route:
        - destination:
            host: httpbin
            port:
              number: 8000
  2. 执行以下命令,部署网关路由规则。

    kubectl apply -f httpbin-gateway.yaml
  3. 执行以下命令,访问测试集群clusterB中的入口网关,查看服务是否正常工作。

    curl http://{clusterB集群的入口网关地址}/headers

    示例输出:

    {
      "headers": {
        "Accept": "*/*",
        "Host": "47.99.XX.XX",
        "User-Agent": "curl/7.79.1",
        "X-Envoy-Attempt-Count": "1",
        "X-Envoy-External-Address": "120.244.XXX.XXX",
        "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=158e4ef69876550c34d10e3bfbd8d43f5ab481b16ba0e90b4e38a2d53ac****;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"
      }
    }

    返回以上结果,表明服务工作正常。

步骤三:在主集群的网格中配置外部访问规则

镜像的服务主机是一个外部域名。您需要添加一个ServiceEntry,指定服务主机Host的DNS解析方式。

  1. 使用以下内容,创建httpbin-cluster-b.yaml文件。

    apiVersion: networking.istio.io/v1alpha3
    kind: ServiceEntry
    metadata:
      name: httpbin-cluster-b
    spec:
      hosts:
      - httpbin.mirror.cluster-b
      location: MESH_EXTERNAL
      ports:
      - number: 80   # 注意此处的端口值是指向集群clusterB的入口网关的端口80。
        name: http
        protocol: HTTP
      resolution: STATIC
      endpoints:
      - address: 47.95.XX.XX # 注意此处的IP值是指向集群clusterB的入口网关地址。
  2. 执行以下命令,部署ServiceEntry。

    kubectl apply -f httpbin-cluster-b.yaml
  3. 使用以下内容,创建httpbin-gateway.yaml文件。

    将100%流量导入到主集群clusterA内的httpbin服务的v1版本。同时,将流量镜像到测试集群clusterB中的服务,通过访问域名httpbin.mirror.cluster-b指向外部的服务地址。

    展开查看httpbin-gateway.yaml

    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: httpbin-gateway
    spec:
      selector:
        istio: ingressgateway
      servers:
      - port:
          number: 80
          name: http
          protocol: HTTP
        hosts:
        - "*"
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: httpbin
    spec:
      gateways:
        - httpbin-gateway
      hosts:
        - '*'
      http:
        - match:
            - uri:
                prefix: /headers
          mirror:
            host: httpbin.mirror.cluster-b
            port:
              number: 80
          mirrorPercentage:
            value: 50
          route:
            - destination:
                host: httpbin
                port:
                  number: 8000
                subset: v1
    重要

    发送到httpbin.mirror.cluster-b的流量和到原始目标的流量完全相同,只有host/authority请求头会被加上-shadow的后缀。上述示例中,镜像流量的host/authority请求头并不是httpbin.mirror.cluster-b,而是原始请求Header加上-shadow后缀。YAML中配置的mirror.host,仅用于查找转发的目的地址,并不会修改原始host Header。

  4. 执行以下命令,部署路由策略。

    kubectl apply -f httpbin-gateway.yaml
  5. 查看主集群中入口网关Pod中的Envoy config_dump

    "routes": [
             {
              "match": {
               "prefix": "/headers",
               "case_sensitive": true
              },
              "route": {
               "cluster": "outbound|8000|v1|httpbin.default.svc.cluster.local",
               "timeout": "0s",
               "retry_policy": {
                "retry_on": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes",
                "num_retries": 2,
                "retry_host_predicate": [
                 {
                  "name": "envoy.retry_host_predicates.previous_hosts",
                  "typed_config": {
                   "@type": "type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate"
                  }
                 }
                ],
                "host_selection_retry_max_attempts": "5",
                "retriable_status_codes": [
                 503
                ]
               },
               "request_mirror_policies": [
                {
                 "cluster": "outbound|80||httpbin.mirror.cluster-b",
                 "runtime_fraction": {
                  "default_value": {
                   "numerator": 500000,
                   "denominator": "MILLION"
                  }
                 },
                 "trace_sampled": false
                }
               ],

    上述示例代码中,request_mirror_policies片段定义请求流量镜像的策略。示例中,cluster表示流量镜像的目标上游服务;runtime_fraction定义流量镜像的比例,即通过numerator字段和denominator字段来表示百万分之500000,也就是50%。