RocketMQ平台的消息灰度方案(2)

简介: RocketMQ平台的消息灰度方案

三、业界MQ灰度方案



(图3.1  灰度调用示意图)


通常,业务灰度只严格地保证RPC服务之间的调用,部分消息灰度流量的流失或错误是可以容忍的,如图3-1所示,V_BFF产生的灰度消息会被V_TRADE的正常版本与灰度版本收到并随机消费,导致部分灰度流量没有进入期望的环境,但整体RPC服务的调用还是隔离了灰度与非灰度环境。当业务对消息消费的逻辑进行了更改,或者不想让灰度的消息影响线上的数据时,MQ的灰度就必须要实现。


由于订阅关系的限制,当前的业界实现的MQ灰度方案都是正常版本与灰度版本使用不同的GroupID来实现。以下的方案均使用了不同的GroupID。


3.1 影子Topic的方案


新建一系列新的Topic来处理隔离灰度的消息。例如对于TOPIC_ORDER会创建TOPIC_ORDER_GRAY来给灰度环境使用。


发送方在发送时,对灰度的消息写入到影子Topic中。消费时,灰度环境只使用灰度的分组订阅灰度的Topic。


3.2 Tag的方案


发送方在发送时,对灰度环境产生的消息的Tag加注灰度标识。消费方,每次灰度版本发布时只订阅灰度Tag的消息,正常的版本订阅非灰度的Tag。


3.3 UserProperty的方案


发送方在发送时,对灰度环境产生的消息的UserProperty加注灰度标识。消费方的客户端需要进行改写,根据UserProperty来过滤,正常的版本会跳过这类消息,灰度的版本会处理灰度消息。


3.4 当前的方案缺陷


以上三种方案各自的优势在这里不做比较,但都存在以下共同的缺陷(也有其它的缺陷或开发诉求,但不致命),无法真正实现灰度状态切换回正常状态时消息不丢失处理,导致整个灰度方案都是从入门到放弃的过程:


  • 因为使用不同的消费组,那么灰度版本验证通过后,如何正确地衔接回原正常版本的消费组的消费位移,做到高效地不丢失信息处理呢?
  • 灰度的消息如何确保准确地消费完毕,做到落在灰度标识的消息做到高效地不丢失信息处理呢?
  • 开启灰度时,灰度消息的位点从那里开始?状态的细节化如何管控?


四、鲁班MQ平台的灰度方案


本质上,MQ灰度问题的核心就是高效地将灰度与非灰度的消息隔离开,消费方按照自己的需求来准确获取到对应版本的消息;当灰度完成后,能够正确地拼接回来消息的位移,做到不丢失处理必要的消息,也就是状态细节上的管理。为了实现这个目的,本方案分别在以下几点进行了改造。


本方案中涉及到的代码为测试代码,主要用于说明方案,实际代码会更精细处理。


4.1 Queue的隔离使用


image.png


(图4.1  Queue的区分使用)


我们已经知道了Queue是topic的实际执行单元,我们的思路就是借助Queue来实现v1(正常)消息、v2(灰度)消息的区分,我们可以固定首尾两条【可配置】Queue专门用来发送与接收灰度的消息,其余的Queue用来发送正常的线上消息。我们使用相同的消费组(也就是和业界的通用方案不一样,我们会使用相同的GroupID),让灰度消费者参与灰度Queue的重平衡,非灰度消费者参与非灰度Queue的重平衡。


这里我们解决了消息的存储隔离问题。


4.2 Broker订阅关系改造


灰度版本往往需要变更Topic或Tag,由于我们没有新增独立的灰度消费组,当灰度版本变更Topic/Tag时,消费组内订阅关系就会不一致,前文也简单解释了订阅关系一致性的原理,我们需要在Broker做出对应的改造,来兼容灰度与非灰度订阅关系不一致的情况。


同一消费组的订阅信息会在维护在ConsumerGroupInfo的subscriptionTable中,可以在ConsumerGroupInfo中增加创建一份graySubscriptionTable用来存储灰度版本的订阅信息,客户端向Broker发送的心跳包会改造成带有自身的灰度标记grayFlag,根据灰度标记grayFlag来选择订阅关系存储在subscriptionTable还是graySubscriptionTable;在拉取消息时,同样向Broker传来grayFlag来选择从subscriptionTable还是graySubscriptionTable中获取对应的订阅信息。


这里我们解决了消费订阅一致性问题。


4.3 Producer的改造


发送方的改造相对简洁,只需确定发送的消息是否为灰度消息,通过实现MessageQueueSelector接口,将灰度消息投递到指定数量的灰度Queue即可。这里我们把用于灰度的grayQueueSize定义到配置中心中去,当前更多是约定使用Broker的指定Queue号作为灰度使用。


TOPIC_V_ORDER共有6条Queue,如图4.2所示,灰度消息只会发送至首尾的0号与5号Queue,非灰度消息则会选择其余的4条Queue发送消息。




(图4.2  发送结果)


这里我们解决了生产者正确投递的问题。


4.4 Consumer的改造


消费方涉及的改造点主要是灰度Queue与非灰度Queue的重平衡分配策略,与各个客户端灰度标记grayFlag的更新与同步。


灰度重平衡策略的核心就是分类处理灰度和非灰度的Queue,要将灰度的Queue分配至灰度ClientID,将非灰度的Queue分配至非灰度的ClientID,因此,在重平衡之前,会通过Namesrv获取同组内的所有客户端clientId对应最新的grayFlag(也就是状态会记录到Namesrv)。


当灰度版本需要变更为线上版本时,各客户端会同步grayFlag到Namesrv,同时,为了避免灰度消息还未消费完成,在更新grayFlag之前会先判断灰度Queue中是否存在未消费的消息,在保证灰度消息消费完成后才会进行grayFlag的更新。


消费者需使用AllocateMessageQueueGray作为重平衡策略,传入灰度Queue的数量,灰度消费者setGrayFlag为true,可以看出只消费了首尾的0号与5号Queue的消息,非灰度消费者setGrayFlag为false,可以看出只会消费中间的4条Queue的消息,在控制台也可以非常清晰的看到Queue的分配结果,grayFlag为true的v2客户端分配到了首尾的Queue,grayFlag为false的v1客户端则分配到了中间的4条Queue。


image.png


image.png


image.png


(图4.3  消费与订阅结果)


当灰度版本需要切换至线上版本时,只需调用updateClientGrayFlag来更新状态即可,可以看出在调用updateClientGrayFlag后,原先v2的两个灰度客户端在消费完灰度Queue的消息后,grayFlag才真正变为false【状态在namesrv保存】,加入到中间的4条非灰度Queue的重平衡中,原先首尾的2条灰度Queue则没有消费者订阅。


image.png



image.png





(图4.4  grayFlag更新)


这里我们解决了状态切换的细节控制处理问题。


4.5 Namesrv的改造


前文提到过,消费者在重平衡时是需要获取组内所有客户端的灰度标识grayFlag,因此,我们需要一个地方来持久化存储这些grayFlag,这个地方是每个消费者都可以访问的,我们选择将这些信息存储在Namesrv。


  • Namesrv相对比较轻量,稳定性很好;
  • 消费者本身就会与Namesrv建立长连接,如果该namesrv挂掉,消费者会自动连接下一个Namesrv,直到有可用连接为止;
  • Broker是实际存储消息的地方,自身运行压力就相对较大,用来做灰度数据的同步一定程度上会加大Broker的压力。


但是Namesrv本身是无状态的节点,节点之间是不会进行信息同步的,灰度数据的一致性需要借助数据库来保证,Namesrv共同访问同一套数据库就好了,数据库持久化存储灰度信息,每次更新v1、v2的灰度状态时,通过Namesrv修改数据库的数据,在每次重平衡之前,再通过Namesrv拉取自己消费组内的所有实例的灰度状态即可。


image.png


(图4.5  Namesrv存储灰度数据示意图)


这里我们解决了状态存储与同步的问题。



相关实践学习
RocketMQ一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
2月前
|
消息中间件 存储 Kafka
【深入浅出 RocketMQ原理及实战】「底层源码挖掘系列」透彻剖析贯穿一下RocketMQ和Kafka索引设计原理和方案
【深入浅出 RocketMQ原理及实战】「底层源码挖掘系列」透彻剖析贯穿一下RocketMQ和Kafka索引设计原理和方案
48 1
|
2月前
|
消息中间件 Kubernetes Docker
KubeSphere 核心实战之三【在kubesphere平台上部署ElasticSearch、应用商店部署RabbitMQ和应用市场部署Zookeeper】(实操篇 3/4)
KubeSphere 核心实战之三【在kubesphere平台上部署ElasticSearch、应用商店部署RabbitMQ和应用市场部署Zookeeper】(实操篇 3/4)
41 0
|
3月前
|
Java 物联网 网络安全
mqtt问题之STM32F103GPRS模组如何接入物理网平台
MQTT接入是指将设备或应用通过MQTT协议接入到消息服务器,以实现数据的发布和订阅;本合集着眼于MQTT接入的流程、配置指导以及常见接入问题的解决方法,帮助用户实现稳定可靠的消息交换。
76 2
|
12月前
|
消息中间件 测试技术 RocketMQ
面试官:使用 RocketMQ 怎么进行灰度发布?
今天来聊一聊 RocketMQ 的灰度方案。 灰度发布是指在黑与白之间,平滑过渡的一种发布方式。在大流量的系统中,如果一次升级改造范围比较大,或者影响内容不太确定,一般会采用切量的方式进行升级,这样可以减少生产变更带来的影响。
|
12月前
|
消息中间件 移动开发 运维
《2023云原生实战案例集》——04 互联网——小七手游 MQTT构筑运营平台与游戏端的交互通道
《2023云原生实战案例集》——04 互联网——小七手游 MQTT构筑运营平台与游戏端的交互通道
|
消息中间件 RocketMQ
RocketMQ平台的消息灰度方案(3)
RocketMQ平台的消息灰度方案
208 0
|
2月前
|
消息中间件 存储 监控
RabbitMQ:分布式系统中的高效消息队列
RabbitMQ:分布式系统中的高效消息队列
|
2月前
|
消息中间件 Java
springboot整合消息队列——RabbitMQ
springboot整合消息队列——RabbitMQ
76 0
|
4月前
|
消息中间件 JSON Java
RabbitMQ消息队列
RabbitMQ消息队列
46 0
|
4月前
|
消息中间件
RabbitMQ 实现消息队列延迟
RabbitMQ 实现消息队列延迟
123 0