服务网格ASM使用FAQ之(4):如何基于集群内服务层和网格层跨集群使用流量镜像

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 流量镜像主要用于能够在不以任何方式影响最终客户端的情况下测试具有实际生产流量的服务。 在实践中,无论是在生产环境还是非生产环境中,将生产流量镜像到测试集群,是降低新部署风险的一种非常有效的方法。像大型互联网企业,多年来也一直在坚持这么做。 服务网格技术提供了流量镜像(Traffic Mirroring)的功能,也称为影子流量(Traffic shadowing),会将实时流量的副本发送到镜像服务, 镜像流量发生在主服务的关键请求路径之外。

什么是流量镜像?

微服务为我们带来了快速开发部署的优秀特性,然而如何降低快速开发部署带来的变更风险成为了一个至关重要的问题。服务网格技术提供了流量镜像(Traffic Mirroring)的功能,也称为影子流量(Traffic shadowing),会将实时流量的副本发送到镜像服务, 镜像流量发生在主服务的关键请求路径之外。这样一来, 可以将生产的流量镜像拷贝到测试集群或者新的测试版本中,在引导实时流量之前进行测试,可以有效地降低版本变更风险,  以尽可能低的风险为生产带来变化的强大的功能


流量镜像有以下优点:

  • 当流量镜像到不同的服务时,会发生在请求的关键路径之外,这样流量镜像产生的任何问题都不会影响到生产环境;
  • 忽略对任何镜像流量的响应,  流量被视为“即发即忘”,镜像实例发回的任何响应都将被忽略, 这样就不会干扰到正常的生产流量的响应;
  • 当流量被镜像时,请求将通过其主机或授权报头发送到镜像服务附上“–shadow”,用以区分流量从何处被镜像到何处;
  • 利用实时生产用例和流量可以有更真实的测试服务环境,有效降低了部署的风险;

启用流量镜像的典型场景

下面介绍几种典型的使用场景可以发挥流量镜像的优势:

  • 线上流量模拟和测试:测试集群的测试可以使用生产实例真实流量,不会影响正常生产的关键路径。比如要用新系统替换掉老旧系统或者系统经历了大规模改造的时候,可以将线上流量导入新系统试运行;一些实验性的架构调整,也可以通过线上流量进行模拟测试。
  • 用于新版本校验:可以实时对比生产流量和镜像流量的输出结果。由于是全样本的模拟,影子流量可以应用于新服务的预上线演练,由于传统的手工测试本身是一种样本化的行为,通过导入真实流量形态,可以完整的模拟线上的所有情况,比如异常的特殊字符,带恶意攻击的token,可以探测预发布服务最真实的处理能力和对异常的处理能力。
  • 用于协作服务版本回退:当用到镜像流量的服务需要修改协作服务时,因为镜像模式添加了-shadow标记, 所以可以正常处理镜像请求,并在提交之前回滚。不会让镜像版本的更改影响生产版本。
  • 隔离测试数据库:与数据处理相关的业务,可以使用空的数据存储并加载测试数据,针对该数据进行镜像流量操作,实现测试数据的隔离。
  • 用于线上问题排查和临时的数据采集,比如对于一些线上突发性问题,在线下流量总是无法复现,这时候可以临时开启一个分支服务,导入影子流量进行调试和排查,而不比影响线上服务。
  • 用于日志行为采集,对于推荐系统和算法来说,样本和数据是非常核心的,传统的自动化测试在算法类的应用所面对的最大的挑战就是无法构建真实环境的用户行为数据,通过影子流量可以将用户行为以日志的形式保存起来,既可以为推荐系统和算法模型构建模拟测试样本数据,也可以作为后续大数据分析用户画像的数据来源再应用到推荐服务中。

如何启用流量镜像

下面是一个简单的 YAML 代码段,显示了如何使用 Istio 启用流量镜像。

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



上面的 VirtualService 将 100%的流量路由到 v1 子集,同时还将相同的流量镜像到该v1-mirroring子集。发送给v1子集的相同请求将被复制并触发该v1-mirroring子集。

最快看到此效果的方法是v1-mirroring在将一些请求发送到应用程序的 v1 版本时查看应用程序的日志。

调用应用程序时您将获得的响应将来自该v1子集。但是,您还将看到请求镜像到该v1-mirroring子集。


基于集群内服务层做流量镜像



下面通过实例来演示一下,先让所有流量都到v1版本,然后使用规则将流量镜像到v1-mirroring版本:


步骤一:配置并启动示例应用服务

首先部署两个版本的httpbin服务:

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---apiVersion: apps/v1
kind: Deployment
metadata:  name: httpbin-v1-mirroring
spec:  replicas: 1  selector:    matchLabels:      app: httpbin
      version: v1-mirroring
  template:    metadata:      labels:        app: httpbin
        version: v1-mirroring
    spec:      serviceAccountName: httpbin
      containers:      - image: docker.io/kennethreitz/httpbin
        imagePullPolicy: IfNotPresent
        name: httpbin
        ports:        - containerPort: 80


然后部署一个客户端应用sleep服务,为curl来提供负载:

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:      terminationGracePeriodSeconds: 0      serviceAccountName: sleep
      containers:      - name: sleep
        image: curlimages/curl
        command: ["/bin/sleep","infinity"]        imagePullPolicy: IfNotPresent
        volumeMounts:        - mountPath: /etc/sleep/tls
          name: secret-volume
      volumes:      - name: secret-volume
        secret:          secretName: sleep-secret
          optional: true---

步骤二:创建路由策略

通过如下控制台来创建新的目标规则,定义2个不同的版本:v1和v1-mirroring

image.png


通过如下控制台来创建新的虚拟服务路由策略,将全部100%的流量导入到v1版本。同时, 将流量镜像到v1-mirroring服务。


image.png



通过如下YAML来创建新的路由策略,将全部100%的流量导入到v1版本。同时, 将流量镜像到v2服务。

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:  name: httpbin
spec:  host: httpbin
  subsets:  - name: v1
    labels:      version: v1
  - name: v1-mirroring
    labels:      version: v1-mirroring
---apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:  name: httpbin-traffic-mirroring
spec:  hosts:    - httpbin
  http:    - route:        - destination:            host: httpbin
            port:              number: 8000            subset: v1
          weight: 100      mirror:        host: httpbin
        port:          number: 8000        subset: v1-mirroring
      mirrorPercentage:        value: 50




步骤三:发送流量请求


等待应用服务运行正常之后,  我们通过sleep应用向httpbin服务发送一些流量:

exportSLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})kubectl exec -it$SLEEP_POD-csleep--curl http://httpbin:8000/headers


可以发现v1和v1-mirroring版本的Pod中有上述请求流量访问的记录, 说明100%的流量在发送到v1版本的同时, 也有50%的流量被镜像到v1-mirroring的pod中,这与上述定义的镜像策略相匹配。

对比两者的日志内容, 可以看到在v1的流量被镜像到了v1-mirroring, 而且日志中的v1-mirroring报文比v1大是流量被标记为影子流量所致, 并且在authority结果中影子流量自动补加了“-shadow”。



基于网格层跨集群流量镜像

基于网关层做流量镜像一般多是用于为预发布环境导入线上真实流量,所以多是跨集群中使用到。 这里以生产环境的集群(clusterA)和 测试集群(clusterB)为例,主体请求在生产环境的集群clusterA上,由它的网关将流量镜像拷贝到集群clusterB中,如下图:



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

首先在测试集群中部署一个版本的httpbin服务:

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---


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


apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:  name: httpbin-gateway
spec:  selector:    istio: ingressgateway # use istio default controller  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

 


然后通过访问集群B中的入口网关, 确认上述测试服务工作正常, 返回相应的请求结果。

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

类似结果如下:

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

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

由于镜像的服务主机是一个外部域名,所以我们这里需要添加一个 ServiceEntry 对服务主机host的 DNS 解析方式进行指定:



apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:  name: httpbin-cluster-b
spec:  hosts:  - httpbin.mirror.cluster-b
  location: MESH_EXTERNAL
  ports:  - number: 80   #注意此处的端口值是指向集群cluster-b的入口网关的端口80    name: http
    protocol: HTTP
  resolution: STATIC
  endpoints:  - address: 47.95.xx.xx #注意此处的IP值是指向集群cluster-b的入口网关地址


然后, 通过如下YAML来创建新的路由策略,将全部100%的流量导入到主集群内的v1版本http服务。同时, 将流量镜像到测试集群B中的服务, 其中通过访问域名httpbin.mirror.cluster-b指向外部的服务地址


apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:  name: httpbin-gateway
spec:  selector:    istio: ingressgateway # use istio default controller  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

 


查看主集群中入口网关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}],


总结

流量镜像主要用于能够在不以任何方式影响最终客户端的情况下测试具有实际生产流量的服务。当我们重写现有服务时,它特别有用,我们想要验证新版本是否可以以相同的方式处理真正的各种传入请求,或者当我们想要在同一服务的两个版本之间进行比较基准测试时。它还可以用于对我们的请求进行一些额外的越界处理,这些处理可以异步完成,例如收集一些额外的统计信息,或者进行一些扩展日志记录。

总之,  在实践中,无论是在生产环境还是非生产环境中,将生产流量镜像到测试集群,是降低新部署风险的一种非常有效的方法。像大型互联网企业,多年来也一直在坚持这么做。服务网格技术提供了一个基于七层负载的影子流量,不管是在集群内创建镜像副本,还是跨集群实现流量复制都可以轻松创建。通过流量镜像我们可以创建一个更接近真实的实验环境,在这个环境下可以进行真实流量下的调试、测试、或者数据采集和流量回放,这让线上工作作业变成一件更可控的事情。而且通过服务网格技术来统一管理网格策略可以统一技术栈,将团队从复杂的技术栈解放出来,极大地降低团队心智负担。

相关文章
|
3月前
|
Prometheus Kubernetes 监控
打造无缝灾备新境界:运用服务网格ASM,将集群外服务无缝融入集群内服务,铸就高可用性坚盾!
【8月更文挑战第2天】随着微服务架构的应用,服务的高可用性变得至关重要。服务网格如阿里巴巴的ASM提供流量管理、服务发现等功能,支撑高可靠服务系统。本文介绍如何利用ASM实现集群外服务作为集群内服务的灾备方案,确保服务连续性。先决条件包括已部署ASM的Kubernetes集群环境及内外部的关键服务副本。通过定义服务条目、配置虚拟服务和目的地规则,可实现自动或手动故障转移。借助ASM的流量管理能力,确保服务高可用性和业务连续性。
52 10
|
3月前
|
Perl
如何利用服务网格ASM使用集群外服务做集群内服务的灾备
本文档指导您如何配置阿里云服务网格(ASM)以实现在多集群环境下,服务间的优先访问及故障转移策略。
114 2
|
5月前
|
Cloud Native 容器 Kubernetes
基于阿里云服务网格流量泳道的全链路流量管理(三):无侵入式的宽松模式泳道
本文简要讨论了使用流量泳道来实现全链路流量灰度管理的场景与方案,并回顾了阿里云服务网格 ASM 提供的严格与宽松两种模式的流量泳道、以及这两种模式各自的优势与挑战。接下来介绍了一种基于 OpenTelemetry 社区提出的 baggage 透传能力实现的无侵入式的宽松模式泳道,这种类型的流量泳道同时具有对业务代码侵入性低、同时保持宽松模式的灵活特性的特点。同时,我们还介绍了新的基于权重的流量引流策略,这种策略可以基于统一的流量匹配规则,将匹配到的流量以设定好的比例分发到不同的流量泳道。
73529 16
基于阿里云服务网格流量泳道的全链路流量管理(三):无侵入式的宽松模式泳道
|
4月前
|
人工智能 自然语言处理 安全
使用阿里云服务网格高效管理LLM流量:(一)流量路由
ASM支持通过LLMProvider和LLMRoute资源管理大型语言模型流量。LLMProvider负责注册LLM服务,LLMRoute负责设定流量规则,应用可灵活切换模型,满足不同场景需求。
|
4月前
|
Cloud Native 测试技术 开发者
阿里云服务网格ASM多集群实践(二):高效按需的应用多环境部署与全链路灰度发布
介绍服务网格ASM提出的一种多集群部署下的多环境部署与全链路灰度发布解决方案。
|
域名解析 存储 网络协议
【服务网格】最佳实践在哪里-2.5:多集群服务发现
在《最佳实践在哪里-2:多集群流量管理》中,我们主要探讨了同一套微服务在多集群环境下的冗余部署以及集群内流量保持实现。不过,多集群部署的使用方式也并非只有这一种;根据实际情况,我们也有可能以其它的方式在多集群中部署服务。比如,我们选择多集群部署可能并非是需要它的故障隔离和故障转移能力,而只是希望服务和其依赖的数据库等外部资源部署在同一地域,以缩短调用时延;在这种情况下,我们可能会将包含多个微服务的
【服务网格】最佳实践在哪里-2.5:多集群服务发现
|
6月前
|
负载均衡 安全 网络协议
如何通过计算巢在ACK集群上使用Istio服务网格
本文主要介绍怎么通过计算巢部署Isito服务网格,并介绍了使用示例。
|
Kubernetes API 容器
基于阿里云服务网格流量泳道的全链路流量管理(二):宽松模式流量泳道
基于阿里云服务网格流量泳道的全链路流量管理(二):宽松模式流量泳道
10972 14
|
Kubernetes Cloud Native 安全
基于阿里云服务网格流量泳道的全链路流量管理(一)严格模式流量泳道
灰度发布是一种常见的对新版本应用服务的发布手段,其特点在于能够将流量在服务的稳定版本和灰度版本之间时刻切换,以帮助我们用更加可靠的方式实现服务的升级。
29958 18
|
6月前
|
Kubernetes Cloud Native 测试技术
使用ASM流量泳道的全链路灰度发布实践
服务网格ASM实现全链路灰度发布:通过流量泳道隔离不同版本环境,配置虚拟服务实现灰度比例控制。从创建泳道、打标签、部署新版本到灰度切流、最终上线及下线旧版。