tft每日頭條

 > 生活

 > rocketmq幂等性解決方案

rocketmq幂等性解決方案

生活 更新时间:2024-10-05 14:03:16

  之前的系列文章中,我們已經通過全鍊路金絲雀發布這個功能來介紹了 MSE 對于全鍊路流量控制的場景,我們已經了解了 spring cloud 和 Dubbo 這一類 RPC 調用的全鍊路灰度應該如何實現,但是沒有涉及到消息這類異步場景下的流量控制,今天我們将以上次介紹過的《如何用 20 分鐘就能獲得同款企業級全鍊路灰度能力?》中的場景為基礎,來進一步介紹消息場景的全鍊路灰度。

  雖然絕大多數業務場景下對于消息的灰度的要求并不像 RPC 的要求得這麼嚴格,但是在以下兩個場景下,還是會對消息的全鍊路有一定的訴求的。

  1、第一種場景是在消息消費時,可能會産生新的 RPC 調用,如果沒有在消息這一環去遵循之前設定好的全鍊路流量控制的規則,會導緻通過消息産生的這部分流量“逃逸”,從而導緻全鍊路灰度的規則遭到破壞,導緻出現不符合預期的情況。

  為了防止出現這個情況,我們需要在消費時候将消息裡原來的流量标複原,并在 RPC 調用的時候遵循原來的規則。我們通過架構圖來詳細描述一下,滿足這個邏輯之後,調用鍊路是怎樣的,從下圖中我們可以看到,灰度和基線環境生産出來的消息,雖然在消息推送的時候是随機的,但是在消費過程中,産生的新的 RPC 調用,還是能夠回到流量原來所屬的環境。

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(1)

  2、第二種場景需要更加嚴格的消息灰度隔離。比如當消息的消費邏輯進行了修改時,這時候希望通過小流量的方式來驗證新的消息消費邏輯的正确性,要嚴格地要求灰度的消息隻能被推送給灰度的消息消費者。

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(2)

  今天我們就來實操一下第二種場景消息的全鍊路灰度,目前 MSE 僅支持 RocketMQ 消息的灰度。若您使用的是開源版 RocketMQ,那麼版本需要在 4.5.0 及以上,若您使用的是阿裡雲商業版 RocketMQ,那麼需要使用鉑金版,且 Ons Client 版本在 1.8.0.Final 及以上。如果隻是想使用第一種場景,隻需要給 B 應用開啟全鍊路灰度的功能即可,不需要做額外的消息灰度相關的配置。

  在這次最佳實踐的操作中,我們是将應用部署在阿裡雲容器服務 Kubernetes 版本,即 ACK 集群來演示,但是事實上,消息灰度對于應用的部署模式是沒有限制性要求的,您可以參考 MSE 幫助文檔,找到自己所使用的部署模式對應的接入方式,也能使用消息全鍊路灰度。

  前提條件開通 MSE 專業版,請參見開通 MSE 微服務治理專業版[1]。創建 ACK 集群,請參見創建 Kubernetes 集群[2]操作步驟 步驟一:接入 MSE 微服務治理

  1、安裝 mse-ack-pilot

  登錄容器服務控制台[3]。在左側導航欄單擊市場 應用目錄。在應用目錄頁面點擊阿裡雲應用,選擇微服務,并單擊 ack-mse-pilot。在 ack-mse-pilot 頁面右側集群列表中選擇集群,然後單擊創建。 rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(3)

  安裝 MSE 微服務治理組件大約需要 2 分鐘,請耐心等待。

  創建成功後,會自動跳轉到目标集群的 Helm 頁面,檢查安裝結果。如果出現以下頁面,展示相關資源,則說明安裝成功。

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(4)

  2、為 ACK 命名空間中的應用開啟 MSE 微服務治理

  登錄 MSE 治理中心控制台[4],如果您尚未開通 MSE 微服務治理,請根據提示開通。在左側導航欄選擇微服務治理中心 Kubernetes 集群列表。在 Kubernetes 集群列表頁面搜索框列表中選擇集群名稱或集群 ID,然後輸入相應的關鍵字,單擊搜索圖标。單擊目标集群操作列的管理。在集群詳情頁面命名空間列表區域,單擊目标命名空間操作列下的開啟微服務治理。在開啟微服務治理對話框中單擊确認。 步驟二:還原線上場景

  首先,我們将分别部署 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 的标準用法,您也可以直接在 htt。部署所使用的 yaml 文件如下,您同樣可以直接在 httspring-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 - - 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 443/TCP 7d service/mqnamesrv ClusterIP 192.168.213.38 9876/TCP 47h service/nacos-server ClusterIP 192.168.24.189 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 的控制台開啟,點擊進入應用的詳情頁,選擇“消息灰度”标簽。

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(6)

  可以看到,在未打标環境忽略的标簽中,我們輸入了 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。

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(7)

  然後,繼續使用 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

  部署完成之後,我們引入流量,并進行驗證

  登錄 MSE 治理中心控制台[4],選擇應用列表。單擊應用 spring-cloud-a 應用詳情菜單,此時可以看到,所有的流量請求都是去往 spring-cloud-a 應用未打标的版本,即穩定版本。 rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(8)

  3.點擊頁面下方的 标簽路由中的添加按鈕,為 spring-cloud-a 應用的 gray 版本設置灰度規則。

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(9)

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(10)

  4.發起流量調用,我們通過 zuul-slb,分别發起流量調用,并查看灰度的情況。

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(11)

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(12)

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(13)

  我們通過 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 調用,也是在基線環境閉環。

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(14)

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(15)

  步驟五:調整消息的标簽過濾規則,并進行驗證

  因為考慮到實際場景中,spring-cloud-c 應用和 spring-cloud-a 應用的所有者可能不是同一個人,不一定能夠做到兩者同時進行灰度發布同步的操作,所以在消息的灰度中,未打标環境默認的行為是消費所有消息。這樣 spring-cloud-c 在進行灰度發布的時候,可以不需要強制 spring-cloud-a 應用也一定要同時灰度發布,且使用相同的環境标。

  spring-cloud-a 在消費時候,未打标環境的行為的選擇權是交給 spring-cloud-a 的所有者,如果需要實現未打标環境不消費 c-gray 生産出來的消息,隻需要在控制台進行配置即可,配置之後實時生效。

  5.調整 spring-cloud-a 未打标環境的過濾規則。比如這裡我們要選擇未打标環境不再消費 gray 環境生産出來的消息,隻需要在“未打标環境忽略的标簽”裡面選擇 gray,然後點擊确定即可。

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(16)

  6.調整規則之後,規則是可以動态地生效,不需要進行重啟的操作,我們直接查看 spring-cloud-a 的日志,驗證規則調整生效。

  從這個日志中,我們可以看到,此時基線環境可以同時消費 gray 和 基線環境生産出來的消息,而且在消費對應環境消息時産生的 Spring Cloud 調用分别路由到 gray 和 基線環境中。

  rocketmq幂等性解決方案(全鍊路灰度之RocketMQ灰度)(17)

  操作總結全鍊路消息灰度的整個過程是不需要修改任何代碼和配置的。目前僅支持 RocketMQ,Client 版本需要在 4.5.0 之後的版本。RocketMQ Server 端需要支持 SQL92 規則過濾,即開源 RocketMQ 需要配置 enablePropertyFilter=true,阿裡雲 RocketMQ 需要使用鉑金版。開啟消息灰度後,MSE Agent 會修改消息消費者的 group,如原來的消費 group 為 group1,環境标簽為 gray,則 group 會被修改成 group1_gray,如果使用的是阿裡雲 RocketMQ,需要提前創建好修改後的 group。開啟和關閉消息灰度後,應用需要重啟才能生效;修改未打标環境忽略的标簽功能可以動态生效,不需要重啟。相關鍊接 [1] MSE 微服務治理專業版:

  htt

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved