通過配置ASMHeaderPropagation實(shí)現(xiàn)寬松模式的流量泳道
本文介紹Baggage作為鏈路透傳的請求頭時,如何通過虛擬服務(wù)以及ASMHeaderPropagation等流量規(guī)則資源的配置實(shí)現(xiàn)寬松模式的流量泳道和流量降級。
前提條件
已創(chuàng)建ASM企業(yè)版或旗艦版實(shí)例,且實(shí)例版本為1.21.6.54及以上。具體操作,請參見創(chuàng)建ASM實(shí)例或升級ASM實(shí)例。
已添加Kubernetes集群到ASM實(shí)例。具體操作,請參見添加集群到ASM實(shí)例。
已創(chuàng)建名稱為ingressgateway的ASM網(wǎng)關(guān)。具體操作,請參見創(chuàng)建入口網(wǎng)關(guān)。
功能介紹
Baggage是OpenTelemetry推出的一種標(biāo)準(zhǔn)化機(jī)制,旨在實(shí)現(xiàn)分布式系統(tǒng)調(diào)用鏈路中跨進(jìn)程傳遞上下文信息。它通過在HTTP頭部增加名為“Baggage”的字段實(shí)現(xiàn),字段值為鍵值對格式,可傳遞租戶ID、追蹤ID、安全憑證等上下文數(shù)據(jù),支持鏈路追蹤、日志關(guān)聯(lián)等功能而無需修改代碼。例如:
baggage: userId=alice,serverNode=DF%2028,isProduction=false
基于透傳的Baggage上下文信息,服務(wù)網(wǎng)格ASM可以利用ASMHeaderPropagation資源幫助您在服務(wù)調(diào)用鏈路上透傳任意請求頭、并基于該請求頭實(shí)現(xiàn)寬松模式的流量泳道。有關(guān)寬松模式的流量泳道,請參見流量泳道概述。
步驟一:配置服務(wù)透傳Baggage上下文
本節(jié)主要展示如何通過OpenTelemetry Operator自動插裝的方法,為Kubernetes集群中的服務(wù)添加Baggage透傳能力。
部署OpenTelemetry Operator。
通過kubectl連接到ASM實(shí)例添加的Kubernetes集群。執(zhí)行以下命令,創(chuàng)建opentelemetry-operator-system命名空間。
kubectl create namespace opentelemetry-operator-system
執(zhí)行以下命令,使用Helm在opentelemetry-operator-system命名空間下安裝OpenTelemetry Operator。(關(guān)于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
執(zhí)行以下命令,檢查opentelemetry-operator是否正常運(yùn)行。
kubectl get pod -n opentelemetry-operator-system
預(yù)期輸出:
NAME READY STATUS RESTARTS AGE opentelemetry-operator-854fb558b5-pvllj 2/2 Running 0 1m
配置自動插裝(auto-instrumentation)。
使用以下內(nèi)容,創(chuàng)建instrumentation.yaml文件。
apiVersion: opentelemetry.io/v1alpha1 kind: Instrumentation metadata: name: demo-instrumentation spec: propagators: - baggage sampler: type: parentbased_traceidratio argument: "1"
執(zhí)行以下命令,在default命名空間下聲明自動插裝。
kubectl apply -f instrumentation.yaml
說明對于OpenTelemetry框架來說,其最佳實(shí)踐還包括部署OpenTelemetry Collector以收集可觀測數(shù)據(jù)。由于本文主要演示OpenTelemetry自動插裝實(shí)現(xiàn)的Baggage鏈路透傳,因此沒有包含部署OpenTelemetry Collector的步驟。有關(guān)服務(wù)網(wǎng)格ASM如何通過OpenTelemetry上報(bào)鏈路追蹤數(shù)據(jù),請參考見將鏈路追蹤數(shù)據(jù)采集到阿里云可觀測鏈路OpenTelemetry版。
步驟二:部署示例服務(wù)
為default命名空間啟用Sidecar網(wǎng)格代理自動注入。具體操作,請參見管理全局命名空間。
說明關(guān)于自動注入的更多信息,請參見配置Sidecar注入策略。
使用以下內(nèi)容,創(chuàng)建mock.yaml文件。
apiVersion: v1 kind: Service metadata: name: mocka labels: app: mocka service: mocka spec: ports: - port: 8000 name: http selector: app: mocka --- apiVersion: apps/v1 kind: Deployment metadata: name: mocka-v1 labels: app: mocka version: v1 spec: replicas: 1 selector: matchLabels: app: mocka version: v1 ASM_TRAFFIC_TAG: v1 template: metadata: labels: app: mocka version: v1 ASM_TRAFFIC_TAG: v1 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v1 - name: app value: mocka - name: upstream_url value: "http://mockb:8000/" ports: - containerPort: 8000 --- apiVersion: v1 kind: Service metadata: name: mockb labels: app: mockb service: mockb spec: ports: - port: 8000 name: http selector: app: mockb --- apiVersion: apps/v1 kind: Deployment metadata: name: mockb-v1 labels: app: mockb version: v1 spec: replicas: 1 selector: matchLabels: app: mockb version: v1 ASM_TRAFFIC_TAG: v1 template: metadata: labels: app: mockb version: v1 ASM_TRAFFIC_TAG: v1 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v1 - name: app value: mockb - name: upstream_url value: "http://mockc:8000/" ports: - containerPort: 8000 --- apiVersion: v1 kind: Service metadata: name: mockc labels: app: mockc service: mockc spec: ports: - port: 8000 name: http selector: app: mockc --- apiVersion: apps/v1 kind: Deployment metadata: name: mockc-v1 labels: app: mockc version: v1 spec: replicas: 1 selector: matchLabels: app: mockc version: v1 ASM_TRAFFIC_TAG: v1 template: metadata: labels: app: mockc version: v1 ASM_TRAFFIC_TAG: v1 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v1 - name: app value: mockc ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mocka-v2 labels: app: mocka version: v2 spec: replicas: 1 selector: matchLabels: app: mocka version: v2 ASM_TRAFFIC_TAG: v2 template: metadata: labels: app: mocka version: v2 ASM_TRAFFIC_TAG: v2 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v2 - name: app value: mocka - name: upstream_url value: "http://mockb:8000/" ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mockb-v2 labels: app: mockb version: v2 spec: replicas: 1 selector: matchLabels: app: mockb version: v2 ASM_TRAFFIC_TAG: v2 template: metadata: labels: app: mockb version: v2 ASM_TRAFFIC_TAG: v2 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v2 - name: app value: mockb - name: upstream_url value: "http://mockc:8000/" ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mockc-v2 labels: app: mockc version: v2 spec: replicas: 1 selector: matchLabels: app: mockc version: v2 ASM_TRAFFIC_TAG: v2 template: metadata: labels: app: mockc version: v2 ASM_TRAFFIC_TAG: v2 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v2 - name: app value: mockc ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mocka-v3 labels: app: mocka version: v3 spec: replicas: 1 selector: matchLabels: app: mocka version: v3 ASM_TRAFFIC_TAG: v3 template: metadata: labels: app: mocka version: v3 ASM_TRAFFIC_TAG: v3 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v3 - name: app value: mocka - name: upstream_url value: "http://mockb:8000/" ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mockb-v3 labels: app: mockb version: v3 spec: replicas: 1 selector: matchLabels: app: mockb version: v3 ASM_TRAFFIC_TAG: v3 template: metadata: labels: app: mockb version: v3 ASM_TRAFFIC_TAG: v3 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v3 - name: app value: mockb - name: upstream_url value: "http://mockc:8000/" ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mockc-v3 labels: app: mockc version: v3 spec: replicas: 1 selector: matchLabels: app: mockc version: v3 ASM_TRAFFIC_TAG: v3 template: metadata: labels: app: mockc version: v3 ASM_TRAFFIC_TAG: v3 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v3 - name: app value: mockc ports: - containerPort: 8000
對于每個實(shí)例服務(wù)Pod,都加入了
instrumentation.opentelemetry.io/inject-java: "true"
和instrumentation.opentelemetry.io/container-names: "default"
兩個注解,以聲明該實(shí)例服務(wù)使用Java語言實(shí)現(xiàn),并要求OpenTelemetry Operator對名稱為default
的容器進(jìn)行自動插裝。執(zhí)行以下命令,部署實(shí)例服務(wù)。
kubectl apply -f mock.yaml
基于OpenTelemetry自動插裝機(jī)制,部署的服務(wù)Pod將自動具有在調(diào)用鏈路中傳遞Baggage的能力。
步驟三:創(chuàng)建流量規(guī)則實(shí)現(xiàn)寬松模式流量泳道
創(chuàng)建DestinationRule流量規(guī)則。
使用以下內(nèi)容,創(chuàng)建dr-mock.yaml文件。
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: dr-mock-default-mocka spec: host: mocka.default.svc.cluster.local subsets: - labels: version: v1 name: v1 - labels: version: v2 name: v2 - labels: version: v3 name: v3 --- apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: dr-mock-default-mockb spec: host: mockb.default.svc.cluster.local subsets: - labels: version: v1 name: v1 - labels: version: v3 name: v3 --- apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: dr-mock-default-mockc spec: host: mockc.default.svc.cluster.local subsets: - labels: version: v1 name: v1 - labels: version: v2 name: v2
此文件表示將mocka、mockb、mockc三個服務(wù)按照Pod的
version
標(biāo)簽分為v1、v2、v3三個版本子集,其中mocka有v1、v2、v3三個版本,mockb有v1、v3兩個版本,mockc有v1、v2兩個版本。通過kubectl連接ASM實(shí)例,執(zhí)行以下命令,創(chuàng)建DestinationRule流量規(guī)則。
kuebctl apply -f dr-mock.yaml
創(chuàng)建ASMHeaderPropagation流量規(guī)則。服務(wù)已經(jīng)實(shí)現(xiàn)了Baggage透傳能力的前提下,可以通過ASMHeaderPropagation流量規(guī)則來指定利用Baggage在鏈路上透傳自定義請求頭。
使用以下內(nèi)容,創(chuàng)建propagation.yaml文件。以下文件表示利用Baggage中的上下文信息,在調(diào)用鏈路中透傳名為
version
的請求頭。apiVersion: istio.alibabacloud.com/v1beta1 kind: ASMHeaderPropagation metadata: name: version-propagation spec: headers: - version
通過kubectl連接ASM實(shí)例,執(zhí)行以下命令, 創(chuàng)建ASMHeaderPropagation流量規(guī)則。
kuebctl apply -f propagation.yaml
創(chuàng)建VirtualService流量規(guī)則。
使用以下內(nèi)容,創(chuàng)建vs-mock.yaml文件。
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: vs-mock-default-mocka spec: hosts: - mocka.default.svc.cluster.local http: - match: - headers: version: exact: v1 route: - destination: host: mocka.default.svc.cluster.local subset: v1 fallback: target: host: mocka.default.svc.cluster.local subset: v1 - match: - headers: version: exact: v2 route: - destination: host: mocka.default.svc.cluster.local subset: v2 fallback: target: host: mocka.default.svc.cluster.local subset: v1 - match: - headers: version: exact: v3 route: - destination: host: mocka.default.svc.cluster.local subset: v3 fallback: target: host: mocka.default.svc.cluster.local subset: v1 --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: vs-mock-default-mockb spec: hosts: - mockb.default.svc.cluster.local http: - match: - headers: version: exact: v1 route: - destination: host: mockb.default.svc.cluster.local subset: v1 fallback: target: host: mockb.default.svc.cluster.local subset: v1 - match: - headers: version: exact: v2 route: - destination: host: mockb.default.svc.cluster.local subset: v2 fallback: target: host: mockb.default.svc.cluster.local subset: v1 - match: - headers: version: exact: v3 route: - destination: host: mockb.default.svc.cluster.local subset: v3 fallback: target: host: mockb.default.svc.cluster.local subset: v1 --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: vs-mock-default-mockc spec: hosts: - mockc.default.svc.cluster.local http: - match: - headers: version: exact: v1 route: - destination: host: mockc.default.svc.cluster.local subset: v1 fallback: target: host: mockc.default.svc.cluster.local subset: v1 - match: - headers: version: exact: v2 route: - destination: host: mockc.default.svc.cluster.local subset: v2 fallback: target: host: mockc.default.svc.cluster.local subset: v1 - match: - headers: version: exact: v3 route: - destination: host: mockc.default.svc.cluster.local subset: v3 fallback: target: host: mockc.default.svc.cluster.local subset: v1
此文件為mocka→mockb→mockc的服務(wù)調(diào)用鏈路創(chuàng)建流量泳道路由規(guī)則。具體來說,是通過匹配調(diào)用鏈路中透傳的version請求頭內(nèi)容、將請求轉(zhuǎn)發(fā)到對應(yīng)的版本(例如,帶有
version: v2
請求頭的請求都發(fā)送到v2版本的服務(wù))。同時,該流量規(guī)則也指定了流量回退規(guī)則:當(dāng)調(diào)用鏈路中的某個服務(wù)的對應(yīng)版本不存在時,統(tǒng)一將請求回退到服務(wù)的v1版本。通過kubectl連接ASM實(shí)例,執(zhí)行以下命令,創(chuàng)建VirtualService流量規(guī)則。
kubectl apply -f vs-mock.yaml
創(chuàng)建網(wǎng)關(guān)引流規(guī)則。
使用以下內(nèi)容,創(chuàng)建gw-mock.yaml文件。
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: mockgw namespace: default spec: selector: istio: ingressgateway servers: - hosts: - '*' port: name: http number: 80 protocol: HTTP --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: swimlane-ingress-vs-weighted-mock namespace: default spec: gateways: - default/mockgw hosts: - '*' http: - name: mock-weighted route: - destination: host: mocka.default.svc.cluster.local subset: v1 headers: request: set: version: v1 weight: 40 - destination: host: mocka.default.svc.cluster.local subset: v2 headers: request: set: version: v2 weight: 30 - destination: host: mocka.default.svc.cluster.local subset: v3 headers: request: set: version: v3 weight: 30
此文件表示為mocka→mockb→mockc的服務(wù)調(diào)用鏈路創(chuàng)建網(wǎng)關(guān)引流規(guī)則。引流方式則為權(quán)重引流,對于發(fā)送到ASM網(wǎng)關(guān)的流量,以4:3:3的比例分別轉(zhuǎn)發(fā)到mocka服務(wù)的v1、v2、v3版本。當(dāng)網(wǎng)關(guān)向mocka服務(wù)轉(zhuǎn)發(fā)請求時,會根據(jù)轉(zhuǎn)發(fā)的目標(biāo)版本為請求添加version請求頭,保證調(diào)用鏈路中存在泳道對應(yīng)的版本信息。
通過kubectl連接ASM實(shí)例,執(zhí)行以下命令,創(chuàng)建網(wǎng)關(guān)引流規(guī)則。
kubectl apply -f gw-mock.yaml
步驟四:驗(yàn)證流量泳道是否生效
獲取ASM網(wǎng)關(guān)的公網(wǎng)IP。具體操作,請參見步驟二:獲取ASM網(wǎng)關(guān)地址。
執(zhí)行以下命令,設(shè)置環(huán)境變量。xxx.xxx.xxx.xxx為上一步獲取的IP。
export ASM_GATEWAY_IP=xxx.xxx.xxx.xxx
驗(yàn)證全灰度鏈路功能是否生效。
執(zhí)行以下命令,查看v1泳道的訪問效果。
for i in {1..100}; do curl http://${ASM_GATEWAY_IP} ; echo ''; sleep 1; done;
預(yù)期輸出:
-> mocka(version: v1, ip: 192.168.1.27)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v1, ip: 192.168.1.27)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v2, ip: 192.168.1.28)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v2, ip: 192.168.1.1) -> mocka(version: v3, ip: 192.168.1.26)-> mockb(version: v3, ip: 192.168.1.29)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v1, ip: 192.168.1.27)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v1, ip: 192.168.1.27)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v2, ip: 192.168.1.28)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v2, ip: 192.168.1.1) -> mocka(version: v2, ip: 192.168.1.28)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v2, ip: 192.168.1.1) -> mocka(version: v2, ip: 192.168.1.28)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v2, ip: 192.168.1.1) -> mocka(version: v2, ip: 192.168.1.28)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v2, ip: 192.168.1.1) -> mocka(version: v3, ip: 192.168.1.26)-> mockb(version: v3, ip: 192.168.1.29)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v1, ip: 192.168.1.27)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v2, ip: 192.168.1.28)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v2, ip: 192.168.1.1) -> mocka(version: v3, ip: 192.168.1.26)-> mockb(version: v3, ip: 192.168.1.29)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v1, ip: 192.168.1.27)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v3, ip: 192.168.1.26)-> mockb(version: v3, ip: 192.168.1.29)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v3, ip: 192.168.1.26)-> mockb(version: v3, ip: 192.168.1.29)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v1, ip: 192.168.1.27)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v3, ip: 192.168.1.26)-> mockb(version: v3, ip: 192.168.1.29)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v2, ip: 192.168.1.28)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v2, ip: 192.168.1.1) -> mocka(version: v1, ip: 192.168.1.27)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v3, ip: 192.168.1.26)-> mockb(version: v3, ip: 192.168.1.29)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v1, ip: 192.168.1.27)-> mockb(version: v1, ip: 192.168.1.30)-> mockc(version: v1, ip: 192.168.1.14) -> mocka(version: v3, ip: 192.168.1.26)-> mockb(version: v3, ip: 192.168.1.29)-> mockc(version: v1, ip: 192.168.1.14)
可以看到,流量將以約4:3:3的比例發(fā)送到服務(wù)調(diào)用鏈路的v1、v2、v3三個版本,并由v1作為基線版本,當(dāng)調(diào)用鏈路中不存在某個服務(wù)的特定版本時,將會調(diào)用該服務(wù)的v1版本。