作者:亦盏
之前的系列文章中,咱们现现已过全链路金丝雀发布这个功用来介绍了 MSE 对于全链路流量操控的场景,咱们现已了解了 Spring Cloud 和 Dubbo 这一类 RPC 调用的全链路灰度应该如何完成,可是没有涉及到音讯这类异步场景下的流量操控,今日咱们将以上次介绍过的《如何用 20 分钟就能取得同款企业级全链路灰度才干?》中的场景为根底,来进一步介绍音讯场景的全链路灰度。
尽管绝大多数事务场景下对于音讯的灰度的要求并不像 RPC 的要求得这么严厉,可是在以下两个场景下,仍是会对音讯的全链路有一定的诉求的。
1、第一种场景是在音讯消费时,可能会发生新的 RPC 调用,假如没有在音讯这一环去遵从之前设定好的全链路流量操控的规矩,会导致经过音讯发生的这部分流量“逃逸”,然后导致全链路灰度的规矩遭到破坏,导致呈现不符合预期的状况。
为了避免呈现这个状况,咱们需求在消费时分将音讯里本来的流量标复原,并在 RPC 调用的时分遵从本来的规矩。咱们经过架构图来详细描绘一下,满足这个逻辑之后,调用链路是怎样的,从下图中咱们能够看到,灰度和基线环境出产出来的音讯,尽管在音讯推送的时分是随机的,可是在消费过程中,发生的新的 RPC 调用,仍是能够回到流量本来所属的环境。
2、第二种场景需求更加严厉的音讯灰度隔离。比方当音讯的消费逻辑进行了修正时,这时分期望经过小流量的方法来验证新的音讯消费逻辑的正确性,要严厉地要求灰度的音讯只能被推送给灰度的音讯顾客。
今日咱们就来实操一下第二种场景音讯的全链路灰度,现在 MSE 仅支撑 RocketMQ 音讯的灰度。若您运用的是开源版 RocketMQ,那么版别需求在 4.5.0 及以上,若您运用的是阿里云商业版 RocketMQ,那么需求运用铂金版,且 Ons Client 版别在 1.8.0.Final 及以上。假如只是想运用第一种场景,只需求给 B 运用敞开全链路灰度的功用即可,不需求做额定的音讯灰度相关的装备。
在这次最佳实践的操作中,咱们是将运用布置在阿里云容器服务 Kubernetes 版别,即 ACK 集群来演示,可是事实上,音讯灰度对于运用的布置形式是没有限制性要求的,您能够参考 MSE 协助文档,找到自己所运用的布置形式对应的接入方法,也能运用音讯全链路灰度。
前提条件
1、注册 MSE 专业版,请参见注册 MSE 微服务办理专业版[1]。
2、创立 ACK 集群,请参见创立 Kubernetes 集群[2]。
操作过程
过程一:接入 MSE 微服务办理
1、装置 mse-ack-pilot
a.登录容器服务操控台[3]。
b.在左侧导航栏单击商场 > 运用目录。
c.在运用目录页面点击阿里云运用,挑选微服务,并单击 ack-mse-pilot。
d.在 ack-mse-pilot 页面右侧集群列表中挑选集群,然后单击创立。
装置 MSE 微服务办理组件大约需求 2 分钟,请耐性等候。
创立成功后,会自动跳转到目标集群的 Helm 页面,检查装置成果。假如呈现以下页面,展现相关资源,则说明装置成功。
2、为 ACK 命名空间中的运用敞开 MSE 微服务办理
a.登录 MSE 办理中心操控台[4],假如您尚未注册 MSE 微服务办理,请依据提示注册。
b.在左侧导航栏挑选微服务办理中心 > Kubernetes 集群列表。
c.在 Kubernetes 集群列表页面搜索框列表中挑选集群称号或集群 ID,然后输入相应的关键字,单击搜索图标。
d.单击目标集群操作列的办理。
e.在集群概况页面命名空间列表区域,单击目标命名空间操作列下的敞开微服务办理。
f.在敞开微服务办理对话框中单击确认。
过程二:复原线上场景
首要,咱们将别离布置 spring-cloud-zuul、spring-cloud-a、spring-cloud-b、spring-cloud-c 这四个事务运用,以及注册中心 Nacos Server 和音讯服务 RocketMQ Server,模拟出一个实在的调用链路。
Demo 运用的结构图下图,运用之间的调用,既包含了 Spring Cloud 的调用,也包含了 Dubbo 的调用,掩盖了当前市面上最常用的两种微服务结构。其中 C 运用会出产出 RocketMQ 音讯,由 A 运用进行消费,A 在消费音讯时,也会建议新的调用。这些运用都是最简单的 Spring Cloud 、 Dubbo 和 RocketMQ 的标准用法,您也能够直接在 github.com/aliyun/alib… 项目上检查源码。
布置之前,简单介绍一下这个调用链路
spring-cloud-zuul 运用在收到 “/A/dubbo” 的恳求时,会把恳求转发给 spring-cloud-a ,然后 spring-cloud-a 经过 dubbo 协议去拜访 spring-cloud-b, spring-cloud-b 也经过 dubbo 协议去拜访 spring-cloud-c,spring-cloud-c 在收到恳求后,会出产一个音讯,并返回自己的环境标签和 ip。这些出产出来的音讯会由 spring-cloud-a 运用消费,spring-cloud-a 运用在消费音讯的时分,会经过 spring cloud 去调用 B,B 从而经过 spring cloud 去调用 C,并且将成果输出到自己的日志中。
当咱们调用 /A/dubbo 的时分
返回值是这样 A[10.25.0.32] -> B[10.25.0.152] -> C[10.25.0.30]
一起,A 运用在接收到音讯之后,输出的日志如下
2021-12-28 10:58:50.301 INFO 1 --- [essageThread_15] c.a.mse.demo.service.MqConsumer : topic:TEST_MQ,producer:C[10.25.0.30],invoke result:A[10.25.0.32] -> B[10.25.0.152] -> C[10.25.0.30]
熟悉了调用链路之后,咱们继续布置运用,您能够运用 kubectl 或许直接运用 ACK 操控台来布置运用。布置所运用的 yaml 文件如下,您相同能够直接在 github.com/aliyun/alib… 上获取对应的源码。
# 布置 Nacos Server
apiVersion: apps/v1
kind: Deployment
metadata:
name: nacos-server
spec:
selector:
matchLabels:
app: nacos-server
template:
metadata:
annotations:
labels:
app: nacos-server
spec:
containers:
- env:
- name: MODE
value: "standalone"
image: registry.cn-shanghai.aliyuncs.com/yizhan/nacos-server:latest
imagePullPolicy: IfNotPresent
name: nacos-server
ports:
- containerPort: 8848
---
apiVersion: v1
kind: Service
metadata:
name: nacos-server
spec:
type: ClusterIP
selector:
app: nacos-server
ports:
- name: http
port: 8848
targetPort: 8848
# 布置事务运用
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-cloud-zuul
spec:
selector:
matchLabels:
app: spring-cloud-zuul
template:
metadata:
annotations:
msePilotCreateAppName: spring-cloud-zuul
labels:
app: spring-cloud-zuul
spec:
containers:
- env:
- name: JAVA_HOME
value: /usr/lib/jvm/java-1.8-openjdk/jre
- name: enable.mq.invoke
value: 'true'
image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-zuul:1.0.0
imagePullPolicy: Always
name: spring-cloud-zuul
ports:
- containerPort: 20000
---
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: slb.s1.small
service.beta.kubernetes.io/alicloud-loadbalancer-address-type: internet
name: zuul-slb
spec:
ports:
- port: 80
protocol: TCP
targetPort: 20000
selector:
app: spring-cloud-zuul
type: LoadBalancer
status:
loadBalancer: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-cloud-a
spec:
selector:
matchLabels:
app: spring-cloud-a
template:
metadata:
annotations:
msePilotCreateAppName: spring-cloud-a
labels:
app: spring-cloud-a
spec:
containers:
- env:
- name: JAVA_HOME
value: /usr/lib/jvm/java-1.8-openjdk/jre
image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:1.0.0
imagePullPolicy: Always
name: spring-cloud-a
ports:
- containerPort: 20001
livenessProbe:
tcpSocket:
port: 20001
initialDelaySeconds: 10
periodSeconds: 30
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-cloud-b
spec:
selector:
matchLabels:
app: spring-cloud-b
template:
metadata:
annotations:
msePilotCreateAppName: spring-cloud-b
labels:
app: spring-cloud-b
spec:
containers:
- env:
- name: JAVA_HOME
value: /usr/lib/jvm/java-1.8-openjdk/jre
image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-b:1.0.0
imagePullPolicy: Always
name: spring-cloud-b
ports:
- containerPort: 20002
livenessProbe:
tcpSocket:
port: 20002
initialDelaySeconds: 10
periodSeconds: 30
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-cloud-c
spec:
selector:
matchLabels:
app: spring-cloud-c
template:
metadata:
annotations:
msePilotCreateAppName: spring-cloud-c
labels:
app: spring-cloud-c
spec:
containers:
- env:
- name: JAVA_HOME
value: /usr/lib/jvm/java-1.8-openjdk/jre
image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:1.0.0
imagePullPolicy: Always
name: spring-cloud-c
ports:
- containerPort: 20003
livenessProbe:
tcpSocket:
port: 20003
initialDelaySeconds: 10
periodSeconds: 30
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: rockectmq-broker
spec:
selector:
matchLabels:
app: rockectmq-broker
template:
metadata:
labels:
app: rockectmq-broker
spec:
containers:
- command:
- sh
- mqbroker
- '-n'
- 'mqnamesrv:9876'
- '-c /home/rocketmq/rocketmq-4.5.0/conf/broker.conf'
env:
- name: ROCKETMQ_HOME
value: /home/rocketmq/rocketmq-4.5.0
image: registry.cn-shanghai.aliyuncs.com/yizhan/rocketmq:4.5.0
imagePullPolicy: Always
name: rockectmq-broker
ports:
- containerPort: 9876
protocol: TCP
- containerPort: 10911
protocol: TCP
- containerPort: 10912
protocol: TCP
- containerPort: 10909
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: rocketmq-name-server
spec:
selector:
matchLabels:
app: rocketmq-name-server
template:
metadata:
labels:
app: rocketmq-name-server
spec:
containers:
- command:
- sh
- mqnamesrv
env:
- name: ROCKETMQ_HOME
value: /home/rocketmq/rocketmq-4.5.0
image: registry.cn-shanghai.aliyuncs.com/yizhan/rocketmq:4.5.0
imagePullPolicy: Always
name: rocketmq-name-server
ports:
- containerPort: 9876
protocol: TCP
- containerPort: 10911
protocol: TCP
- containerPort: 10912
protocol: TCP
- containerPort: 10909
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: mqnamesrv
spec:
type: ClusterIP
selector:
app: rocketmq-name-server
ports:
- name: mqnamesrv-9876-9876
port: 9876
targetPort: 9876
装置成功后,示例如下:
➜ ~ kubectl get svc,deploy
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 192.168.0.1 <none> 443/TCP 7d
service/mqnamesrv ClusterIP 192.168.213.38 <none> 9876/TCP 47h
service/nacos-server ClusterIP 192.168.24.189 <none> 8848/TCP 47h
service/zuul-slb LoadBalancer 192.168.189.111 123.56.253.4 80:30260/TCP 47h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nacos-server 1/1 1 1 4m
deployment.apps/rockectmq-broker 1/1 1 1 4m
deployment.apps/rocketmq-name-server 1/1 1 1 5m
deployment.apps/spring-cloud-a 1/1 1 1 5m
deployment.apps/spring-cloud-b 1/1 1 1 5m
deployment.apps/spring-cloud-c 1/1 1 1 5m
deployment.apps/spring-cloud-zuul 1/1 1 1 5m
一起这儿咱们能够经过 zuul-slb 来验证一下方才所说的调用链路
➜ ~ curl http://123.56.253.4/A/dubbo
A[10.25.0.32] -> B[10.25.0.152] -> C[10.25.0.30]
过程三:敞开音讯灰度功用
现在依据操控台的提示,在音讯的出产者 spring-cloud-c 和音讯的顾客 spring-cloud-a 都敞开音讯的灰度。咱们直接经过 MSE 的操控台敞开,点击进入运用的概况页,挑选“音讯灰度”标签。
能够看到,在未打标环境疏忽的标签中,咱们输入了 gray,这儿意味着,带着 gray 环境标的音讯,只能由 spring-cloud-a-gray 消费,不能由 spring-cloud-a 来消费。
1、这儿需求额定说明一下,由于考虑到实践场景中,spring-cloud-c 运用和 spring-cloud-a 运用的一切者可能不是同一个人,纷歧定能够做到两者一起进行灰度发布同步的操作,所以在音讯的灰度中,未打标环境默许的行为是消费一切音讯。这样 spring-cloud-c 在进行灰度发布的时分,能够不需求强制 spring-cloud-a 运用也一定要一起灰度发布。
2、咱们把未打标环境消费行为的挑选权交给 spring-cloud-a 的一切者,假如需求完成未打标环境不消费 c-gray 出产出来的音讯,只需求在操控台进行装备即可,装备之后实时收效。
-
运用此功用您无需修正运用的代码和装备。
-
音讯的出产者和音讯的顾客,需求一起敞开音讯灰度,音讯的灰度功用才干收效。
-
音讯类型现在只支撑 RocketMQ,包含开源版别和阿里云商业版。
-
假如您运用开源 RocketMQ,则 RocketMQ Server 和 RocketMQ Client 都需求运用 4.5.0 及以上版别。
-
假如您运用阿里云 RocketMQ,需求运用铂金版,且 Ons Client 运用 1.8.0.Final 及以上版别。
-
-
敞开音讯灰度后,MSE 会修正音讯的 Consumer Group。例如本来的 Consumer Group 为 group1,环境标签为 gray,敞开音讯灰度后,则 group 会被修正成 group1_gray,假如您运用的是阿里云 RocketMQ ,请提早创立好 group。
-
默许运用 SQL92 的过滤方法,假如您运用的开源 RocketMQ,需求在服务端敞开此功用(即在 broker.conf 中装备 enablePropertyFilter=true)。
-
默许状况下,未打标节点将消费一切环境的音讯,若需求指定 未打标环节点 不消费 某个标签环境出产出来的音讯,请装备“未打标环境疏忽的标签”,修正此装备后动态收效,无需重启运用。
过程四:重启节点,布置新版别运用,并引进流量进行验证
首要,由于敞开和封闭运用的音讯灰度功用后都需求重启节点才干收效,所以首要咱们需求重启一下 spring-cloud-a 和 spring-cloud-c 运用,重启的方法能够在操控台上挑选重新布置,或许直接运用 kubectl 指令删去现有的 pod。
然后,继续运用 yaml 文件的方法在 Kubernetes 集群中布置新版别的 spring-cloud-a-gray、spring-cloud-b-gray 和 spring-cloud-c-gray
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-cloud-a-gray
spec:
selector:
matchLabels:
app: spring-cloud-a-gray
template:
metadata:
annotations:
alicloud.service.tag: gray
msePilotCreateAppName: spring-cloud-a
labels:
app: spring-cloud-a-gray
spec:
containers:
- env:
- name: JAVA_HOME
value: /usr/lib/jvm/java-1.8-openjdk/jre
image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:1.0.0
imagePullPolicy: Always
name: spring-cloud-a-gray
ports:
- containerPort: 20001
livenessProbe:
tcpSocket:
port: 20001
initialDelaySeconds: 10
periodSeconds: 30
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-cloud-b-gray
spec:
selector:
matchLabels:
app: spring-cloud-b-gray
template:
metadata:
annotations:
alicloud.service.tag: gray
msePilotCreateAppName: spring-cloud-b
labels:
app: spring-cloud-b-gray
spec:
containers:
- env:
- name: JAVA_HOME
value: /usr/lib/jvm/java-1.8-openjdk/jre
image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-b:1.0.0
imagePullPolicy: Always
name: spring-cloud-b-gray
ports:
- containerPort: 20002
livenessProbe:
tcpSocket:
port: 20002
initialDelaySeconds: 10
periodSeconds: 30
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-cloud-c-gray
spec:
selector:
matchLabels:
app: spring-cloud-c-gray
template:
metadata:
annotations:
alicloud.service.tag: gray
msePilotCreateAppName: spring-cloud-c
labels:
app: spring-cloud-c-gray
spec:
containers:
- env:
- name: JAVA_HOME
value: /usr/lib/jvm/java-1.8-openjdk/jre
image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:1.0.0
imagePullPolicy: Always
name: spring-cloud-c-gray
ports:
- containerPort: 20003
livenessProbe:
tcpSocket:
port: 20003
initialDelaySeconds: 10
periodSeconds: 30
1、布置完成之后,咱们引进流量,并进行验证
2、登录 MSE 办理中心操控台[4],挑选运用列表。
单击运用 spring-cloud-a 运用概况菜单,此刻能够看到,一切的流量恳求都是去往 spring-cloud-a 运用未打标的版别,即稳定版别。
点击页面下方的 标签路由中的添加按钮,为 spring-cloud-a 运用的 gray 版别设置灰度规矩。
建议流量调用,咱们经过 zuul-slb,别离建议流量调用,并检查灰度的状况。
咱们经过 spring-cloud-a 和 spring-cloud-a-gray 的日志去检查音讯消费的状况。能够看到,音讯的灰度功用现已收效, spring-cloud-a-gray 这个环境,只会消费带有 gray 标的音讯,spring-cloud-a 这个环境,只会消费未打标的流量出产出来的音讯。
在截图中咱们能够看见,spring-cloud-a-gray 环境输出的日志 topic:TEST_MQ, producer: Cgray [10.25.0.102] , invoke result: Agray[10.25.0.101] -> Bgray[10.25.0.25] -> Cgray[10.25.0.102], spring-cloud-a-gray 只会消费 Cgray 出产出来的音讯,并且消费音讯过程中建议的 Spring Cloud 调用,成果也是 Agray[10.25.0.101] -> Bgray[10.25.0.25] -> Cgray[10.25.0.102],即在灰度环境闭环。
而 spring-cloud-a 这个环境,输出的日志为 topic:TEST_MQ,producer:C[10.25.0.157],invoke result:A[10.25.0.100] -> B[10.25.0.152] -> C[10.25.0.157],只会消费 C 的基线环境出产出来的音讯,且在这个过程中建议的 Spring Cloud 调用,也是在基线环境闭环。
过程五:调整音讯的标签过滤规矩,并进行验证
由于考虑到实践场景中,spring-cloud-c 运用和 spring-cloud-a 运用的一切者可能不是同一个人,纷歧定能够做到两者一起进行灰度发布同步的操作,所以在音讯的灰度中,未打标环境默许的行为是消费一切音讯。这样 spring-cloud-c 在进行灰度发布的时分,能够不需求强制 spring-cloud-a 运用也一定要一起灰度发布,且运用相同的环境标。
spring-cloud-a 在消费时分,未打标环境的行为的挑选权是交给 spring-cloud-a 的一切者,假如需求完成未打标环境不消费 c-gray 出产出来的音讯,只需求在操控台进行装备即可,装备之后实时收效。
1、调整 spring-cloud-a 未打标环境的过滤规矩。比方这儿咱们要挑选未打标环境不再消费 gray 环境出产出来的音讯,只需求在“未打标环境疏忽的标签”里边挑选 gray,然后点击确定即可。
2、调整规矩之后,规矩是能够动态地收效,不需求进行重启的操作,咱们直接检查 spring-cloud-a 的日志,验证规矩调整收效。
从这个日志中,咱们能够看到,此刻基线环境能够一起消费 gray 和 基线环境出产出来的音讯,并且在消费对应环境音讯时发生的 Spring Cloud 调用别离路由到 gray 和 基线环境中。
操作总结
1、全链路音讯灰度的整个过程是不需求修正任何代码和装备的。
2、现在仅支撑 RocketMQ,Client 版别需求在 4.5.0 之后的版别。RocketMQ Server 端需求支撑 SQL92 规矩过滤,即开源 RocketMQ 需求装备 enablePropertyFilter=true,阿里云 RocketMQ 需求运用铂金版。
3、敞开音讯灰度后,MSE Agent 会修正音讯顾客的 group,如本来的消费 group 为 group1,环境标签为 gray,则 group 会被修正成 group1_gray,假如运用的是阿里云 RocketMQ,需求提早创立好修正后的 group。
4、敞开和封闭音讯灰度后,运用需求重启才干收效;修正未打标环境疏忽的标签功用能够动态收效,不需求重启。
相关链接
[1] MSE 微服务办理专业版:
help.aliyun.com/document_de…
[2] Kubernetes 集群:
help.aliyun.com/document_de…
[3] 容器服务操控台:
cs.console.aliyun.com/
[4] MSE 办理中心操控台
mse.console.aliyun.com/#/msc/home
点击此处,前往 MSE 官网检查更多概况!
发布云原生技能最新资讯、聚集云原生技能最全内容,定期举行云原生活动、直播,阿里产品及用户最佳实践发布。与你并肩探索云原生技能点滴,共享你需求的云原生内容。
重视【阿里巴巴云原生】大众号,获取更多云原生实时资讯!