基于阿里云服务网格流量泳道的全链路流量管理(三):无侵入式的宽松模式泳道

作者:尹航

在前文《基于阿里云服务网格流量泳道的全链路流量管理(一):严格模式流量泳道》、《基于阿里云服务网格流量泳道的全链路流量管理(二):宽松模式流量泳道》中,我们介绍了流量泳道的概念、使用流量泳道进行全链路灰度管理的方案,以及阿里云服务网格 ASM 提供的严格模式与宽松模式的流量泳道。在本文中,我们将介绍一种基于 OpenTelemetry 自动插装方案实现的宽松模式流量泳道场景,无需任何业务代码改造即可为运行在 Kubernetes 集群中的云原生应用实现灵活的全链路灰度管理能力。

概述

流量泳道是将一个云原生应用中的多个服务根据服务版本(或其他特征)隔离成的多个独立的运行环境。

在严格模式下,每条流量泳道中包含应用的调用链路上的全部服务,对于应用程序则没有任何要求。

而在宽松模式下,您只需要确保创建一条包含调用链路中所有服务的泳道:基线泳道。其它泳道可以不包含调用链路上的全部服务。当一个泳道中的服务进行相互调用时,若目标服务在当前泳道中不存在,则请求将被转发到基线泳道中的相同服务,并在请求目标存在当前泳道中存在时将请求重新转发回当前泳道。宽松模式的流量泳道虽然可以实现灵活的全链路灰度,但要求应用程序必须包含一个能够在整条调用链路中透传的请求头(链路透传请求头)。

阿里云服务网格 ASM 已经提供一种基于 baggage 透传的全新宽松模式流量泳道方案,能够在不改造业务代码的情况下,实现泳道服务的灵活灰度。

背景介绍

OpenTelemetry 是云原生计算基金会(Cloud Native Computing Foundation, CNCF)的一个项目,与其他 CNCF 项目如 Kubernetes、Prometheus 和 Envoy 等紧密相连,共同构建了云原生技术生态系统的基础。由于其提供的丰富功能和广泛适用性,OpenTelemetry 在业内已经确立了其领导地位,越来越多的企业和开发者采用它作为构建和维护可观测性平台的核心组件。

baggage 是由 OpenTelemetry 制定并推动的、在分布式系统调用链路中传递链路上下文信息的标准。它具体表现为一个名为 baggage 的请求头,其内部包含了以键值对形式存储的链路上下文信息,例如:

baggage: userId=alice,serverNode=DF%2028,isProduction=false

您可以使用 OpenTelemetry 提供的 SDK,在服务调用链路中传递 baggage 请求头、进而在整条服务链路上传递自定义的上下文信息。当服务部署在 Kubernentes 集群中时,则可以通过 OpenTelemetry Operator 的自动插装来为服务提供 baggage 透传能力、而无需修改业务代码。有关 baggage 的详细信息,可以参考 baggage [ 1]

基于 baggage 的透传,阿里云服务网格 ASM 提供了一种无需修改代码即可实现的宽松模式流量泳道,并针对流量泳道的引流策略进行了增强,支持基于流量权重策略对不同的泳道进行引流。本文将首先使用 OpenTelemetry 自动插装来为服务引用透传 baggage 请求头的能力,接下来创建宽松模式下的三条泳道,并基于流量权重策略对不同的泳道进行引流。

演示:实现服务 baggage 透传与宽松模式流量泳道

前提条件

  • 已创建 ASM 企业版或旗舰版实例,且版本为 1.21.6.54 及以上。具体操作,请参见创建 ASM 实例 [ 2]
  • 已添加集群到 ASM 实例。具体操作,请参见添加集群到 ASM 实例 [ 3]
  • 已创建名称为 ingressgateway 的 ASM 网关。具体操作,请参见创建入口网关服务 [ 4]
  • 已创建名称为 ingressgateway 且命名空间为 istio-system 的网关规则。具体操作,请参见管理网关规则 [ 5]
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:name: ingressgatewaynamespace: istio-system
spec:selector:istio: ingressgatewayservers:- port:number: 80name: httpprotocol: HTTPhosts:- '*'

步骤一:配置服务透传 baggage 上下文

本节主要展示如何通过 OpenTelemetry Operator 自动插装的方法,为 Kubernetes 集群中的服务添加 baggage 透传能力。

  1. 部署 OpenTelemetry Operator。

a. 通过 kubectl 连接到 ASM 实例添加的 Kubernetes 集群。执行以下命令,创建 opentelemetry-operator-system 命名空间。

kubectl create namespace opentelemetry-operator-system

b. 执行以下命令,使用 Helm 在 opentelemetry-operator-system 命名空间下安装 OpenTelemetry Operator。(如果尚未安装 Helm,可以参考安装 Helm 来安装 Helm 命令行工具。)

helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm install \--namespace=opentelemetry-operator-system \--version=0.46.0 \--set admissionWebhooks.certManager.enabled=false \--set admissionWebhooks.certManager.autoGenerateCert=true \--set manager.image.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/opentelemetry-operator" \--set manager.image.tag="0.92.1" \--set kubeRBACProxy.image.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/kube-rbac-proxy" \--set kubeRBACProxy.image.tag="v0.13.1" \--set manager.collectorImage.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/opentelemetry-collector" \--set manager.collectorImage.tag="0.97.0" \--set manager.opampBridgeImage.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/operator-opamp-bridge" \--set manager.opampBridgeImage.tag="0.97.0" \--set manager.targetAllocatorImage.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/target-allocator" \--set manager.targetAllocatorImage.tag="0.97.0" \--set manager.autoInstrumentationImage.java.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/autoinstrumentation-java" \--set manager.autoInstrumentationImage.java.tag="1.32.1" \--set manager.autoInstrumentationImage.nodejs.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/autoinstrumentation-nodejs" \--set manager.autoInstrumentationImage.nodejs.tag="0.49.1" \--set manager.autoInstrumentationImage.python.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/autoinstrumentation-python" \--set manager.autoInstrumentationImage.python.tag="0.44b0" \--set manager.autoInstrumentationImage.dotnet.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/autoinstrumentation-dotnet" \--set manager.autoInstrumentationImage.dotnet.tag="1.2.0" \--set manager.autoInstrumentationImage.go.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/opentelemetry-go-instrumentation" \--set manager.autoInstrumentationImage.go.tag="v0.10.1.alpha-2-aliyun" \opentelemetry-operator open-telemetry/opentelemetry-operator

c. 执行以下命令,检查 opentelemetry-operator 是否正常运行。

kubectl get pod -n opentelemetry-operator-system

预期输出:

NAME READY   STATUS    RESTARTS   AGE
opentelemetry-operator-854fb558b5-pvllj   2/2     Running   0          1m
  1. 配置自动插装(auto-instrumentation)。

a. 使用以下内容,创建 instrumentation.yaml 文件。

apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:name: demo-instrumentation
spec:propagators:- baggagesampler:type: parentbased_traceidratioargument: "1"

b. 执行以下命令,在 default 命名空间下声明自动插装。

kubectl apply -f instrumentation.yaml

🔔 说明: 对于 OpenTelemetry 框架来说,其最佳实践还包括部署 OpenTelemetry Collector 以收集可观测数据。由于本文主要演示 OpenTelemetry 自动插装实现的 baggage 链路透传,因此没有包含部署 OpenTelemetry Collector 的步骤。

步骤二:部署示例服务

  1. 为 default 命名空间启用 Siedcar 网格代理自动注入。具体操作,请参见开启  Sidecar 自动注入 [ 6]

关于自动注入的更多信息,请参见配置 Sidecar 注入策略。

  1. 使用以下内容,创建 mock.yaml 文件。
apiVersion: v1
kind: Service
metadata:name: mockalabels:app: mockaservice: mocka
spec:ports:- port: 8000name: httpselector:app: mocka
---
apiVersion: apps/v1
kind: Deployment
metadata:name: mocka-v1labels:app: mockaversion: v1
spec:replicas: 1selector:matchLabels:app: mockaversion: v1ASM_TRAFFIC_TAG: v1template:metadata:labels:app: mockaversion: v1ASM_TRAFFIC_TAG: v1annotations:instrumentation.opentelemetry.io/inject-java: "true"instrumentation.opentelemetry.io/container-names: "default"spec:containers:- name: defaultimage: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-javaimagePullPolicy: IfNotPresentenv:- name: versionvalue: v1- name: appvalue: mocka- name: upstream_urlvalue: "http://mockb:8000/"ports:- containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:name: mockblabels:app: mockbservice: mockb
spec:ports:- port: 8000name: httpselector:app: mockb
---
apiVersion: apps/v1
kind: Deployment
metadata:name: mockb-v1labels:app: mockbversion: v1
spec:replicas: 1selector:matchLabels:app: mockbversion: v1ASM_TRAFFIC_TAG: v1template:metadata:labels:app: mockbversion: v1ASM_TRAFFIC_TAG: v1annotations:instrumentation.opentelemetry.io/inject-java: "true"instrumentation.opentelemetry.io/container-names: "default"spec:containers:- name: defaultimage: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-javaimagePullPolicy: IfNotPresentenv:- name: versionvalue: v1- name: appvalue: mockb- name: upstream_urlvalue: "http://mockc:8000/"ports:- containerPort: 8000---
apiVersion: v1
kind: Service
metadata:name: mockclabels:app: mockcservice: mockc
spec:ports:- port: 8000name: httpselector:app: mockc
---
apiVersion: apps/v1
kind: Deployment
metadata:name: mockc-v1labels:app: mockcversion: v1
spec:replicas: 1selector:matchLabels:app: mockcversion: v1ASM_TRAFFIC_TAG: v1template:metadata:labels:app: mockcversion: v1ASM_TRAFFIC_TAG: v1annotations:instrumentation.opentelemetry.io/inject-java: "true"instrumentation.opentelemetry.io/container-names: "default"spec:containers:- name: defaultimage: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-javaimagePullPolicy: IfNotPresentenv:- name: versionvalue: v1- name: appvalue: mockcports:- containerPort: 8000
---
apiVersion: apps/v1
kind: Deployment
metadata:name: mocka-v2labels:app: mockaversion: v2
spec:replicas: 1selector:matchLabels:app: mockaversion: v2ASM_TRAFFIC_TAG: v2template:metadata:labels:app: mockaversion: v2ASM_TRAFFIC_TAG: v2annotations:instrumentation.opentelemetry.io/inject-java: "true"instrumentation.opentelemetry.io/container-names: "default"spec:containers:- name: defaultimage: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-javaimagePullPolicy: IfNotPresentenv:- name: versionvalue: v2- name: appvalue: mocka- name: upstream_urlvalue: "http://mockb:8000/"ports:- containerPort: 8000
---
apiVersion: apps/v1
kind: Deployment
metadata:name: mockb-v2labels:app: mockbversion: v2
spec:replicas: 1selector:matchLabels:app: mockbversion: v2ASM_TRAFFIC_TAG: v2template:metadata:labels:app: mockbversion: v2ASM_TRAFFIC_TAG: v2annotations:instrumentation.opentelemetry.io/inject-java: "true"instrumentation.opentelemetry.io/container-names: "default"spec:containers:- name: defaultimage: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-javaimagePullPolicy: IfNotPresentenv:- name: versionvalue: v2- name: appvalue: mockb- name: upstream_urlvalue: "http://mockc:8000/"ports:- containerPort: 8000---
apiVersion: apps/v1
kind: Deployment
metadata:name: mockc-v2labels:app: mockcversion: v2
spec:replicas: 1selector:matchLabels:app: mockcversion: v2ASM_TRAFFIC_TAG: v2template:metadata:labels:app: mockcversion: v2ASM_TRAFFIC_TAG: v2annotations:instrumentation.opentelemetry.io/inject-java: "true"instrumentation.opentelemetry.io/container-names: "default"spec:containers:- name: defaultimage: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-javaimagePullPolicy: IfNotPresentenv:- name: versionvalue: v2- name: appvalue: mockcports:- containerPort: 8000
---
apiVersion: apps/v1
kind: Deployment
metadata:name: mocka-v3labels:app: mockaversion: v3
spec:replicas: 1selector:matchLabels:app: mockaversion: v3ASM_TRAFFIC_TAG: v3template:metadata:labels:app: mockaversion: v3ASM_TRAFFIC_TAG: v3annotations:instrumentation.opentelemetry.io/inject-java: "true"instrumentation.opentelemetry.io/container-names: "default"spec:containers:- name: defaultimage: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-javaimagePullPolicy: IfNotPresentenv:- name: versionvalue: v3- name: appvalue: mocka- name: upstream_urlvalue: "http://mockb:8000/"ports:- containerPort: 8000
---
apiVersion: apps/v1
kind: Deployment
metadata:name: mockb-v3labels:app: mockbversion: v3
spec:replicas: 1selector:matchLabels:app: mockbversion: v3ASM_TRAFFIC_TAG: v3template:metadata:labels:app: mockbversion: v3ASM_TRAFFIC_TAG: v3annotations:instrumentation.opentelemetry.io/inject-java: "true"instrumentation.opentelemetry.io/container-names: "default"spec:containers:- name: defaultimage: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-javaimagePullPolicy: IfNotPresentenv:- name: versionvalue: v3- name: appvalue: mockb- name: upstream_urlvalue: "http://mockc:8000/"ports:- containerPort: 8000---
apiVersion: apps/v1
kind: Deployment
metadata:name: mockc-v3labels:app: mockcversion: v3
spec:replicas: 1selector:matchLabels:app: mockcversion: v3ASM_TRAFFIC_TAG: v3template:metadata:labels:app: mockcversion: v3ASM_TRAFFIC_TAG: v3annotations:instrumentation.opentelemetry.io/inject-java: "true"instrumentation.opentelemetry.io/container-names: "default"spec:containers:- name: defaultimage: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-javaimagePullPolicy: IfNotPresentenv:- name: versionvalue: v3- name: appvalue: mockcports:- containerPort: 8000

对于每个实例服务 Pod,都加入了 instrumentation.opentelemetry.io/inject-java: "true"和instrumentation.opentelemetry.io/container-names: "default"两个注解,以声明该实例服务使用 java 语言实现,并要求 OpenTelemetry Operator 对名称为 default 的容器进行自动插装。

  1. 执行以下指令,部署实例服务。
kubectl apply -f mock.yaml

基于 OpenTelemetry 自动插装机制,部署的服务 Pod 将自动具有在调用链路中传递 baggage 的能力。

步骤三:创建泳道组和对应泳道

  1. 创建泳道组。

a. 登录 ASM 控制台 [ 7] ,在左侧导航栏,选择服务网格 > 网格管理

b. 在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择流量管理中心 > 流量泳道

c. 在流量泳道页面,单击创建泳道组,在创建泳道组面板,配置相关信息,然后单击确定

image.png

  1. 创建 s1、s2、s3 泳道,并分别绑定 v1、v2、v3 版本。

a. 在流量泳道页面的流量规则定义区域,单击创建泳道

b. 在创建泳道对话框,配置相关信息,然后单击确定

image.png

创建 s1 泳道的示例图如下:

图片

三个泳道创建完成后,示例效果如下。默认情况下,您在泳道组中创建的第一个泳道将被设定为基线泳道。您也可以修改基线泳道,当流量发往其它泳道中不存在的服务时,通过回退机制将请求转发至基线泳道。关于修改基线泳道的具体操作,请参见修改基线泳道 [ 8]

图片

三个泳道创建完成后,针对泳道组中的每个服务都将生成泳道规则对应的目标规则 DestinationRule 和虚拟服务 VirtualService。您可以在控制台左侧导航栏,选择流量管理中心 > 目标规则虚拟服务进行查看。例如,针对 mocka 服务会自动创建如下 DestinationRule 和 VirtualService。

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:labels:asm-system: 'true'provider: asmswimlane-group: testname: trafficlabel-dr-test-default-mockanamespace: istio-system
spec:host: mocka.default.svc.cluster.localsubsets:- labels:ASM_TRAFFIC_TAG: v1name: s1- labels:ASM_TRAFFIC_TAG: v2name: s2apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:labels:asm-system: 'true'provider: asmswimlane-group: testname: trafficlabel-vs-test-default-mockanamespace: istio-system
spec:hosts:- mocka.default.svc.cluster.localhttp:- match:- headers:x-asm-prefer-tag:exact: s1route:- destination:host: mocka.default.svc.cluster.localsubset: s1fallback:target:host: mocka.default.svc.cluster.localsubset: s1- match:- headers:x-asm-prefer-tag:exact: s2route:- destination:host: mocka.default.svc.cluster.localsubset: s2fallback:target:host: mocka.default.svc.cluster.localsubset: s1- match:- headers:x-asm-prefer-tag:exact: s3route:- destination:host: mocka.default.svc.cluster.localsubset: s3fallback:target:host: mocka.default.svc.cluster.localsubset: s1
  1. 创建基于权重的统一引流规则。

a. 在流量泳道页面的流量规则定义区域,单击引流策略中的基于权重引流

b. 在设定统一引流规则对话框,配置相关信息,然后单击确定。本文以泳道服务对应入口 API 为 /mock 为例,为三条泳道配置统一的引流规则。

image.png

设定统一引流规则的示例图如下:

图片

  1. 设定三条泳道的引流权重,引流权重确定了流量向每条泳道发送的比例。

a. 在流量泳道页面的流量规则定义区域,在每条泳道的引流权重列,单击数字右侧的图片按钮,在编辑引流权重对话框,配置相关信息,然后单击确定

image.png

编辑流量权重的示例图如下:

图片

步骤四:验证全链路灰度功能是否生效

  1. 获取 ASM 网关的公网 IP。具体操作,请参见获取 ASM 网关地址 [ 9]

  2. 执行以下命令,设置环境变量。xxx.xxx.xxx.xxx 为上一步获取的 IP。

export ASM_GATEWAY_IP=xxx.xxx.xxx.xxx
  1. 验证全链路灰度功能是否生效。

a. 执行以下命令,查看三条泳道的访问效果。

for i in {1..100}; do curl http://${ASM_GATEWAY_IP}/mock ;  echo ''; sleep 1; done;

预期输出:

-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189)
-> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)

由预期输出得到,流量将以约 6:2:2 的比例发送到 s1、s2、s3 泳道,并由 s1 作为基线泳道,当调用链路中不存在某个服务的特定版本时,将会调用 s1 泳道中的对应服务。

总结

本文简要讨论了使用流量泳道来实现全链路流量灰度管理的场景与方案,并回顾了阿里云服务网格 ASM 提供的严格与宽松两种模式的流量泳道、以及这两种模式各自的优势与挑战。接下来介绍了一种基于 OpenTelemetry 社区提出的 baggage 透传能力实现的无侵入式的宽松模式泳道,这种类型的流量泳道同时具有对业务代码侵入性低、同时保持宽松模式的灵活特性的特点。同时,我们还介绍了新的基于权重的流量引流策略,这种策略可以基于统一的流量匹配规则,将匹配到的流量以设定好的比例分发到不同的流量泳道。

相关链接:

[1] baggage

https://opentelemetry.io/docs/concepts/signals/baggage/

[2] 创建 ASM 实例

https://help.aliyun.com/document_detail/147793.html#task-2370657

[3] 添加集群到 ASM 实例

https://help.aliyun.com/document_detail/148231.html#task-2372122

[4] 创建入口网关服务

https://help.aliyun.com/document_detail/150510.html#task-2372970

[5] 管理网关规则

https://help.aliyun.com/document_detail/150504.html

[6] 开启 Sidecar 自动注入

https://help.aliyun.com/document_detail/186136.html#task-1962690

[7] ASM 控制台

https://servicemesh.console.aliyun.com/

[8] 修改基线泳道

https://help.aliyun.com/zh/asm/user-guide/scenario-1-the-drainage-request-header-is-not-transmitted-in#0561972057jqm

[9] 获取 ASM 网关地址

https://help.aliyun.com/document_detail/444079.html#section-ida-zt6-md7

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/341946.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wpf工程中加入Hardcodet.NotifyIcon.Wpf生成托盘

1、在项目中用nuget引入Hardcodet.NotifyIcon.Wpf。如下图所示。 2、在App.xaml中创建托盘界面&#xff0c;代码是写在 App.xaml 里面 注意在application中一定要加入这一行代码&#xff1a; xmlns:tb"http://www.hardcodet.net/taskbar" 然后在<Application.R…

【免费Web系列】JavaWeb实战项目案例七(项目结束)

这是Web第一天的课程大家可以传送过去学习 http://t.csdnimg.cn/K547r 登录认证 在前面的课程中&#xff0c;我们已经实现了部门管理、员工管理的基本功能&#xff0c;但是大家会发现&#xff0c;我们并没有登录&#xff0c;就直接访问到了Tlias智能学习辅助系统的后台。 这…

韩国Neowine推出第三代强加密芯片ALPU-CV

推出第三代加密芯片&#xff1b;是ALPU系列中的高端IC&#xff1b;是一款高性能车规级加密芯片&#xff1b;其加密性更强、低耗电、体积小&#xff1b;使得防复制、防抄袭板子的加密性能大大提升&#xff0c;该芯片通过《AEC-Q100》认证&#xff0c;目前已经在国产前装车辆配件…

亚马逊测评自养号需要什么资源?

亚马逊测评自养号项目需要用到哪些资源呢&#xff1f; 1. 养号系统及软件 2. 代理IP资源 3. 收货地址及注册资料 4. 国外信用卡及礼品卡 5. 邮箱及手机号想做好这个项目以上的资源缺一不可 首先我们来说说养号的环境&#xff0c;养号的环境在以前的文章里也提到过&#x…

基于python的网上挂号预约系统-计算机毕业设计源码89352

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;医院当然也不例外。网上挂号预约系统是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;采用Py…

软件三班20240605

文章目录 1.创建工程和模块2.添加 web支持3.创建前端代码4.添加servlet 依赖5. 代码6.案例2 1.创建工程和模块 2.添加 web支持 方法1 方法2 3.创建前端代码 4.添加servlet 依赖 5. 代码 <!DOCTYPE html> <html lang"en"> <head><meta c…

【面试干货】SQL中count(*)、count(1)和count(column)的区别与用法

【面试干货】SQL中count&#xff08;*&#xff09;、count&#xff08;1&#xff09;和count&#xff08;column&#xff09;的区别与用法 1、count(*)2、count(1)3、count(column) &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在SQL中&a…

InnoDB存储引擎非常重要的一个机制--MVCC(多版本并发控制)

Mysql是如何实现隔离性的&#xff1f;&#xff08;锁MVCC&#xff09; 隔离性是指一个事务内部的操作以及操作的数据对正在进行的其他事务是隔离的&#xff0c;并发执行的各个事务之间不能相互干扰。隔离性可以防止多个事务并发执行时&#xff0c;可能存在交叉执行导致数据的不…

opencv进阶 ——(十一)基于RMBG实现生活照生成寸照

实现步骤 1、检测人脸&#xff0c;可以使用opencv自带的级联分类器或者dlib实现人脸检测 2、放大人脸范围&#xff0c;调整到正常寸照尺寸 3、基于RMGB算法得到人像掩码 4、生成尺寸相同的纯色背景与当前人像进行ALPHA融合即可 alpha融合实现 void alphaBlend(cv::Mat&…

c++(内存分配,构造,析构)

#include <iostream>using namespace std; class Per { private:string name;int age;double *height;double *weigh; public://无参构造Per(){cout << "Per::无参构造" << endl;}//有参构造Per(string name,int age,double height,double weigh):…

分布式锁redisson

1&#xff1a;pom.xml添加依赖 <dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.21.1</version> </dependency>2-1&#xff1a;方法一&#xff1a;读取默认ym…

新书速览|Python Django 4构建动态网站的16堂课

Python Django 4构建动态网站的16堂课 本书内容 《Python Django 4构建动态网站的16堂课》是一本关于Django框架的网站开发入门教材&#xff0c;适合想要学习并掌握Django框架的开发人员阅读。《Python Django 4构建动态网站的16堂课》共分16课&#xff0c;内容包括网站开发环境…

C++ STL - 容器

C STL&#xff08;标准模板库&#xff09;中的容器是一组通用的、可复用的数据结构&#xff0c;用于存储和管理不同类型的数据。 目录 零. 简介&#xff1a; 一 . vector&#xff08;动态数组&#xff09; 二. list&#xff08;双向链表&#xff09; 三. deque&#xff08…

磁盘未格式化:深度解析、恢复方案及预防之道

在当今这个信息化爆炸的时代&#xff0c;磁盘未格式化问题无疑成为了众多用户头疼的难题。当我们的存储设备突然提示“磁盘未格式化”时&#xff0c;数据的丢失与恢复的挑战便摆在了我们面前。本文将深入解析磁盘未格式化的现象、原因&#xff0c;并给出两种有效的数据恢复方案…

MYSQL数据库细节详细分析

MYSQL数据库的数据类型(一般只需要用到这些) 整型类型&#xff1a;用于存储整数值&#xff0c;可以选择不同的大小范围来适应特定的整数值。 TINYINTSMALLINTMEDIUMINTINTBIGINT 浮点型类型&#xff1a;用于存储带有小数部分的数值&#xff0c;提供了单精度&#xff08;FLOA…

uniapp小程序开发 | 从零实现一款影视类app (后台接口实现,go-zero微服务的使用)

uniapp小程序开发实战系列&#xff0c;完整介绍从零实现一款影视类小程序。包含小程序前端和后台接口的全部完整实现。系列连载中&#xff0c;喜欢的可以点击收藏。 该篇着重介绍获取轮播图后台接口和获取正在热映电影的两个后台接口的实现。 后台服务使用golang&#xff0c;…

解决MAC M1 Docker Desktop启动一直在starting

问题描述&#xff1a; 今天使用docker buildx 构建Multi-platform&#xff0c;提示如下错误&#xff1a; ERROR: Multi-platform build is not supported for the docker driver. Switch to a different driver, or turn on the containerd image store, and try again. 于是按…

关系代数与规范化

本文是根据自己的理解&#xff0c;结合实践整理所得&#xff0c;有兴趣的可以参考学习。

在k8s中部署Kafka高可用集群超详细讲解

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《数据流专家&#xff1a;Kafka探索》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Kafka简介 2、为什么在Kubernetes中部署Kafka 二、…

金融科技发展报告:移动支付的市场格局、趋势与优缺点

一、引言 随着科技的飞速发展,金融科技已成为推动全球经济发展的重要力量。移动支付作为金融科技的重要分支,其市场格局与趋势日益受到业界的关注。本报告将详细剖析移动支付的市场格局,并深入探讨其发展趋势,同时结合相关案例和数据,为读者呈现移动支付的优缺点,以及国…