简介:本文将以上次介绍过的《如何用 20 分钟就能获得同款企业级全链路灰度能力?》中的场景为基础,来进一步介绍消息场景的全链路灰度。
虽然绝大多数业务场景下对于消息的灰度的要求并不像 RPC 的要求得这么严格,但是在以下两个场景下,还是会对消息的全链路有一定的诉求的。
2、第二种场景需要更加严格的消息灰度隔离。比如当消息的消费逻辑进行了修改时,这时候希望通过小流量的方式来验证新的消息消费逻辑的正确性,要严格地要求灰度的消息只能被推送给灰度的消息消费者。
前提条件
操作步骤
- 登录容器服务控制台**[3]**。
- 在左侧导航栏单击市场 > 应用目录。
- 在应用目录页面点击阿里云应用,选择微服务,并单击 ack-mse-pilot。
- 在 ack-mse-pilot 页面右侧集群列表中选择集群,然后单击创建。
安装 MSE 微服务治理组件大约需要 2 分钟,请耐心等待。
创建成功后,会自动跳转到目标集群的 Helm 页面,检查安装结果。如果出现以下页面,展示相关资源,则说明安装成功。
- 登录 MSE 治理中心控制台**[4]**,如果您尚未开通 MSE 微服务治理,请根据提示开通。
在左侧导航栏选择微服务治理中心 > Kubernetes 集群列表。- 在 Kubernetes 集群列表页面搜索框列表中选择集群名称或集群 ID,然后输入相应的关键字,单击搜索图标。
- 单击目标集群操作列的管理。
- 在集群详情页面命名空间列表区域,单击目标命名空间操作列下的开启微服务治理。
- 在开启微服务治理对话框中单击确认。
当我们调用 /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 文件如下,您同样可以直接在
# 部署 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]
可以看到,在未打标环境忽略的标签中,我们输入了 gray,这里意味着,带着 gray 环境标的消息,只能由 spring-cloud-a-gray 消费,不能由 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)。
- 默认情况下,未打标节点将消费所有环境的消息,若需要指定 未打标环节点 不消费 某个标签环境生产出来的消息,请配置“未打标环境忽略的标签”,修改此配置后动态生效,无需重启应用。
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
- 登录 MSE 治理中心控制台**[4],选择应用列表**。
- 单击应用 spring-cloud-a 应用详情菜单,此时可以看到,所有的流量请求都是去往 spring-cloud-a 应用未打标的版本,即稳定版本。
从这个日志中,我们可以看到,此时基线环境可以同时消费 gray 和 基线环境生产出来的消息,而且在消费对应环境消息时产生的 Spring Cloud 调用分别路由到 gray 和 基线环境中。
操作总结
- 全链路消息灰度的整个过程是不需要修改任何代码和配置的。
- 目前仅支持 RocketMQ,Client 版本需要在 4.5.0 之后的版本。RocketMQ Server 端需要支持 SQL92 规则过滤,即开源 RocketMQ 需要配置 enablePropertyFilter=true,阿里云 RocketMQ 需要使用铂金版。
- 开启消息灰度后,MSE Agent 会修改消息消费者的 group,如原来的消费 group 为 group1,环境标签为 gray,则 group 会被修改成 group1_gray,如果使用的是阿里云 RocketMQ,需要提前创建好修改后的 group。
- 开启和关闭消息灰度后,应用需要重启才能生效;修改未打标环境忽略的标签功能可以动态生效,不需要重启。
mse.console.aliyun.com/#/msc/home
本文为阿里云原创内容,未经允许不得转载。