乐趣区

关于阿里云:vivo-鲁班平台-RocketMQ-消息灰度方案

本文作者:区二立 – vivo 技术架构总监

计划背景

RocketMQ 应用宽泛,技术场景下,能够用于异步解耦,比方不同零碎间调用业务链上做分段式解决或应用不同语言的两个零碎间的解耦;能够用于数据同步,比方根底数据通过 MQ 播送到各个业务畛域,实现业务畛域的提效;高并发订单或 IM 的推送服务中,能够应用 MQ 做削峰填谷;此外,在分布式事务中,也能够通过 MQ 做最终一致性的事务计划。

RocketMQ 在业务场景下可笼罩很多零碎,包含营销零碎、生产制作上的各种管控零碎、公共平台上人资、挪动办公等流程类零碎、相似于钉钉的自建 IM 工具以及大数据等。

随着以微服务化为根底的数字化建设转型,实现一项业务必须串联不同团队和不同利用。而不同利用的开发和公布周期绝对独立,须要对接的版本不一,因而须要灰度计划。

对于 HTTP 的灰度,很多时候通用的网关即可提供较好的反对,甚至简略地用 Nginx 实现也能够达到成果。微服务层,以 Dubbo 为例,有各种分组比方有扩大的 SPI 补充实现,能够轻松解决灰度方面的困扰。而 MQ 的灰度却没有规范反对,很多零碎间接放弃了 MQ 灰度,因而也不得不承受肯定时间段内的谬误重试。

MQ 技术特点

Broker 是音讯服务的外围,提供了音讯服务最重要的计算与存储性能。音讯发送时会对应一个 Topic,Topic 为逻辑上的概念,外部执行往往是以 Queue 为单位。以一般音讯类型的 Topic 为例,Topic 个别有多个 Queue,如图中的 TOPIC_V_PLACE_ORDER 共有四个 Queue,别离在两个 broker 里,broker a 与 broker b 里各有两个 Queue。任何一条音讯都必然属于四个 Queue 中的某一条。

每条音讯内可指定 tag 标记,用于在逻辑上进一步切分 topic,如上图中的 tagA、tagB。切分维度有多种,能够是 IoT,也能够是增值服务类的产品 order 等。不同 tab 示意不同分类,但它们共享一个 topic。

Queue 能够了解为物理上的辨别,broker 的 commitLog 用于寄存音讯。commitLog 不辨别 Topic 和 Queue,不同的 Topic 音讯内容会按理论接管的 Queue 存储到其对应的 broker commitLog 上,该音讯只会在集群中的某个 broker commitlog 中存在。

Broker commitLog 是专用的,到达某一个 broker 的音讯都会存在同一个 commitLog 上,即一个 commitLog 会同时保留不同 topic 的内容。

CommitLog 达到肯定大小时(个别为 1G),会新建新的 commitLog 用于存储和接管新音讯。commitLog 在物理上存储具体音讯,因而必然须要文件记录 Queue 与 commitLog 存储音讯之间的地位映射。minOffset(最小位移)和 maxOffset(最大位移)也是存储地位中的重要概念。

ConsumeGroupID 与 groupID 强关联,groupID 生产时会在 broker 上记录 topic Queue 的生产位移,即会依据 Queue 记录不同 groupID 的 consumerOffset。

无论是生产者还是消费者,MQ 都应用 groupID 示意交互的角色。在集群生产的状况下,应用同一个 groupID 的两个 client 会做 Queue 的生产订阅调配,个别会尽量采取平分的形式。而独立的生产组比方上图中 GID_V_PAYMENT,会独占 topic 中的 4 条 Queue。生产组之间互相独立、互不烦扰,有各自的生产位移点。

不同的 RocketMQ 实例都有独立的 clientID,作为惟一标识与 broker 打交道。

提交生产位点时,只能提交该生产位点前都已实现音讯位移的音讯。如上图,3、4 两条音讯都已被生产线程解决实现,但 2 仍然在解决中,因而理论触发的提交位点为 1。音讯 2 实现解决后,会触发音讯 4 的提交。

不同的 groupID 之间相互绝缘,但同一个 groupID 却会相互影响。订阅关系指标记了以后利用实例的 groupID 订阅了哪些 Topic(或 topic 的 tag)。每一个利用实例或 clientID 的订阅关系都会随着心跳包一起发送到 broker 上,并在 broker 上以 groupID 作为 key 来存储。

每个 broker 每次接管到不同实例的心跳包时,都会按 groupID 的维度校验、替换订阅关系,即同一个 groupID 的订阅关系会被替换。同一个 groupID 在不同利用实例、不同 clientID,只有订阅的 Topic 和 tag 有任何不同,都会被最初到来的心跳包的订阅关系笼罩。

如果在不同的利用实例中应用同一个 groupID,而实例因版本起因导致订阅 Topic 发生变化,则两组实例共存时会相互烦扰,导致有些利用实例收不到想要的音讯或收到谬误的音讯。而订阅关系是影响 MQ 灰度计划的外围因素。

上图 clientID_001 和 clientID_002 同属一个生产组 GID_C_INVENTORY,clientID_001 订阅了 TOPIC_A,clientID_002 订阅 TOPIC_B,都应用同一生产组执行订阅,因而,依照调配策略,它们会被穿插调配。调配后果可能是 clientID_001 和 clientID_002 平分 TOPIC_A 的两条 Queue,也可能会平分 TOPIC_B 的两条 Queue,从而导致异样。这就是订阅形式不统一导致的调配错乱以及解决错乱。

常见灰度计划

惯例的灰度计划个别都会抉择不同的生产组,解决形式有影子 Topic、Tag 过滤以及 userProperty 过滤。以上几种解决形式都会存在一些缺点:比方如何保障所有灰度音讯都被生产结束?灰度须要切换时,如何保障灰度音讯是被灰度环境生产?灰度订阅切换为失常订阅关系的时候,如何确认生产位点,如何连接能力保障音讯不失落?此外,运维人员可能对 RocketMQ 或利用外部逻辑不分明,理论的操控对运维人员而言也是微小的挑战。

鲁班灰度计划

鲁班灰度计划的外围解决思路是将 Queue 隔离应用。

Queue 是 Topic 的理论执行单元,一个 Topic 有多个 Queue。能够抉择一部分 Queue 用于灰度,灰度 Queue 的数量、开始地位等能够在具体的实现里进行定义。如上图,首尾两个 Queue 专门用于灰度。因而,咱们只需保障生产者与消费者的灰度与失常环境隔离应用即可,灰度环境的音讯只从灰度的 Queue 里取,失常环境的音讯从失常环境的 Queue 里拉取。

消费者中无论是灰度还是失常的利用集群,都应用同一个生产组。这会导致订阅关系非常容易不统一。针对于此,咱们的解决方案是革新订阅关系。

Broker 的订阅关系保护在 ConsumerGroupInfo 里,其中 subscriptionTable 负责保护 groupID 发送来的订阅心跳包。如果心跳包的订阅关系不一样,则会进行替换。咱们新增了 graySubscriptionTable 类,专门负责保护灰度的订阅关系。尽管是同一个 groupID,但应用不同的类来别离保护灰度和非灰度的订阅关系。

生产者的发送策略如下:首先判断指标 topic 是否有灰度消费者,再判断以后音讯是否属于灰度范畴。如果是,则将灰度隐没投递到灰度的 Queue 里;否则,投递到失常的 Queue。

消费者按灰度拉取,失常集群只平分失常的 Queue,灰度集群只平分灰度的 Queue。如上图,ClientID_001 与 ClientID_002 只会分享失常的 Queue,而 ClientID_003 与 ClientID_004 只分享灰度的 Queue,他们共用一个生产组。

如果本生产组应用的 topic 没有灰度,但因为其余生产组影响波及到灰度 topic,则它也会平分拉取灰度的 Queue。此外,如果 topic 没有波及灰度集群,则灰度 Queue 会空置不应用,消费者不拉取,生产者不发送。将灰度集群切换为失常集群时,原先灰度的集群会保障将灰度 Queue 生产实现后才真正进行切换,业务上动静切换服务时,MQ 会主动依据理论生产进度进行细节上的管控,保障所有音讯不抛弃。

除了业务灰度标识外,MQ 也有本人的灰度标识须要解决,存储于 Namesrv。生产者和消费者获取 Topic 路由音讯都由 Namesrv 提供,这也意味着生产者和消费者曾经与 Namesrv 建设了连贯。能够通过定期将灰度音讯更新到 Namesrv 上,生产者也会定期将灰度信息拉到本地来买通整个链路。

Namesrv 存储灰度关系时,须要一个有状态的数据库来进行保留。

如果灰度期间的延时音讯在灰度完结后才投递,则会投递到失常 Queue。延时音讯长期存在数据库里,可能反对比拟细粒度的延时定义。

全局程序音讯会由一条 Queue 变成两条 Queue。咱们批改了创立 Queue 的定义,灰度切换回失常环境时,会保障将灰度的音讯解决完当前再解决失常的音讯。

细节上的管制次要依赖灰度开关 grayFlag 和 graySwitch 两个标识位进行管制。

graySwitch 标记应用灰度的逻辑以及平分所有 Topic 里 Queue 的逻辑,可能兼容不参加灰度的利用,能够平分所有受其余灰度生产组影响的 Topic 的所有 Queue。

grayFlag 用于标记本实例是否为灰度实例,这会影响到订阅关系的保留。它会先查看 graySwitch,再进行本人的判断。

灰度场景校验

实际是测验真谛的唯一标准,咱们进行了具体的灰度性能校验,别离是灰度版本订阅的 topic&tag 不变、灰度版本订阅的 topic 减少、灰度版本订阅的 topic 缩小、灰度版本订阅的 tage 变动以及灰度版本订阅的 topic&tag 混合变动。

退出 Apache RocketMQ 社区

十年铸剑,Apache RocketMQ 的成长离不开寰球靠近 500 位开发者的积极参与奉献,置信在下个版本你就是 Apache RocketMQ 的贡献者,在社区不仅能够结识社区大牛,晋升技术水平,也能够晋升集体影响力,促成本身成长。

社区 5.0 版本正在进行着热火朝天的开发,另外还有靠近 30 个 SIG(兴趣小组)等你加​入,欢送立志打造世界级分布式系统的同学退出社区,增加社区开发者微信:rocketmq666 即可进群,参加奉献,打造下一代音讯、事件、流交融解决平台。

微信扫码增加小火箭进群

另外还能够退出钉钉群与 RocketMQ 爱好者一起宽泛探讨:

钉钉扫码加群

关注「Apache RocketMQ」公众号,获取更多技术干货

退出移动版