当前位置: 首页>后端>正文

rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq

前面通过对 rabbitmq 的分析,我们总结一张结构图放在这里(图引自),作为和 rocketmq 的对比。

rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq,rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq_负载均衡,第1张

图中的队列是 quorum 队列。每个 broker 上都会有不同的队列存在。因为 quorum 队列采用了raft 协议,所以队列分为领导者队列和追随者队列,基于 raft 协议来保障领导者队列和追随者队列之间的数据同步和自动选主。

但是 rabbitmq 虽然受众广泛,并且拥有许多种语言的客户端实现。但是因其 erlang 语言生态不是特别的热门,而一般大厂中真正落地都需要进行深度定制,所以本篇我们基于前面的 rabbitmq 的知识,来对比学习下由阿里巴巴出品的 rocketmq ,官方文档链接在此。


首先我们关注单个 Broker 内部的结构,如下图,引自




rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq,rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq_rabbitmq_02,第2张


同 rabbitmq 一样,rocketmq 中的 topic 可以对应 rabbitmq 的 exchange,属于逻辑概念,是关联队列的规则。可以简单认为队列仍然是存储消息的地方。不过 rocketmq 有所不同,在逻辑上我们可以认为:

  • topicA
  • queue0
  • queue1
  • topicB
  • queue5

但是实际每个 Broker 上,存储的地方只有一个,那就是图中的 CommitLog,Commitlog 可以对比 mysql 中的binlog。同样是顺序写入,而且会产生多个 commitlog 文件(因为每个 commitlog 文件默认是1G大小),文件中的内容就是一条条消息内容。

这样就相当于多个topic的消息都混杂写入到了 commitlog 文件中。那么该如何区分呢?

答案就对应图中的 ConsumerQueue ,其保存了属于某个 topic 下的消息。但是仅仅保存某条消息在 commitlog 中的偏移量,以及消费者对本队列中的消息消费的偏移量等等。所以 consumerQueue 相当于 commitlog 的索引,真正存储消息内容的还是 commitlog。

到这里,我们就得出一个重要的结论:Broker 上存储消息内容的地方是 commitlog,所以集群环境下的可靠性也就是要同步 commitlog。这个结论是理解后续集群架构的重要依据。

同样的,消息可靠性先来关注单机 Broker。根据 rocketmq 文档可知,和 rabbitmq 一样,可以配置同步刷盘还是异步刷盘,异步刷盘是刷新到操作系统的 Page cache 中,实际是没有真正落入物理磁盘的。

如果是同步刷盘,则生产者发布一条消息,Broker 将其写入到 commitlog 文件后,消息就不会丢失。异步刷盘则可能存在落盘前断电丢失的危险,但是同步刷盘降低性能,需要结合实际场景进行选择。


rocketmq 的集群架构如下:(图片来源)

rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq,rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq_消息队列_03,第3张

前文我们提到过 raft 集群中,读写只能从领导者节点读取,那么如何突破单领导者性能瓶颈呢?rocketmq 的架构设计告诉了我们答案。通过引入 NameServer (类似 zookeeper),将 Broker 扩展成多个小集群。巧合的是,rocketmq 在 4.5版本之后,同样是引入了 raft 算法来实现Broker集群的。

所以图中 Broker Cluster 下的 Broker Master 1和2,实际上就是两个 raft 集群的 Leader。raft 引入的目的主要是:

  • 在集群内同步 commitlog 内容
  • 自动选主自动切换

集群内的交互方式我们已经熟悉了,就是 raft 那一套。那么集群外, producer、consumer、namerServer、和 broker cluster 是怎么配合的呢?

当 Broker 启动时,会主动向所有的 nameServer 注册(注册 Broker 的IP信息,Broker上的topic信息等),这样 nameServer就知道了 Broker-topic-queue 的联系了。

注意,这里之所以要向所有的nameServer都注册,是可以让每个 nameServer 上都存储全部的注册信息,从而避免 nameServer 之间的数据同步。又由于注册这个动作并不是经常性的,所以也不会造成性能上的影响。

那么当生产者准备向一个 topic 写入消息时,首先要知道和哪个 Broker 通信。所以生产者会先从 NamerServer 上获取到该 topic 在哪些 Broker 上有存储。又由于 Broker 内部需要建立 commitlog 和 consumerQueue 的联系,所以生产者会轮询选择该 topic 下的一个队列进行发送,发送时已知该队列处于哪个 Broker 上。

消费者同样是去 namerServer 上获取 Broker-topic-queue 之间的联系,从而去连接到对应的 Broker 上,进行队列的消息消费。


队列模型与发布-订阅模型

理解了单机和集群的架构之后,我们再来对比一下 rabbitmq 和 rocketmq 关于两种消息模型的实现,即:队列模型和发布-订阅模型。并以此来理解 rocketmq (或者说是 kafka)中的关键概念:消费者组和消费位置。

队列模型:



rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq,rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq_rabbitmq_04,第4张


生产者发送消息到(某个)队列中,消费者们从队列中消费消息。但是消费者之间是竞争的关系,即对于消息M1,只能由一个消费者消费掉。这就是典型的队列模型。

而发布-订阅模型中,生产者往一个主题发布消息,任何订阅该主题的消费者 都能收到 该消息内容。这就是发布订阅模型。那么 rabbitmq 实现发布-订阅模型就是提出了 exchange 的概念,通过不同类型的 exchange,将消息发送到 不同的队列。但是这就相当于一条消息被物理地复制了多次。



rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq,rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq_负载均衡_05,第5张


为了实现 发布-订阅模型,并且避免一条消息被复制多次,rocketmq 引入了 消费者组 的概念。

首先是消息分发机制,和之前一样,一个 topic 下的消息被分发到不同的 queue(consumerQueue)中。那么针对同一个 queue ,可以有多个属于不同消费者组的消费者来消费,并且相互不影响。也就是说同一消费者组内的消费者仍然是竞争关系,不同消费者组之间的消费者都可以独立消费该队列的全部消息数据。

这样,每个消费者组就能收到发往该主题的全量消息,而消费者组内的消费者,只能收到该主题的部分消息。消费者组内部成员就可以起到对 topic 消息进行负载均衡的作用。而消费者组之间互不影响的特性,也可以带来灵活性。

所以,我们同样来看一下 rocketmq 是如何实现队列模型的,如下图:



rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq,rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq_消息队列_06,第6张


实际是利用同一消费者组,内部的消费者只能收到部分消息(即某一个队列的消息)特性来实现。

而实现发布-订阅模型,则是一个队列可能同时被多个消费者组消费,而消费者组之间的消费进度互不影响。如下图:



rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq,rocketMQ 版本和springboot 兼容版本 rocketmq与rabbitmq_数据同步_07,第7张


重平衡(rebalance)

由于引入了消费者组的概念,而组内成员之间消费是互斥的。所以当组内成员变更时,就需要重新为各个成员分配要消费的队列,以此达到一种负载均衡的效果。这种机制,就是大名鼎鼎的重平衡机制。

不过 rocketmq 中的实现相对来说简单一些。重平衡可以拆分为三大步:

  1. 判断并发起
  2. 计算平衡结果
  3. 执行

首先是计算平衡结果的算法,可以简单认为就是轮流分配机制。比如一个topic下有10个队列,该topic的消费者组中有3个消费者,那么经过平衡算法的计算,最终会是 3,3,4 的队列分配结果。

然后重平衡的发起方是消费者,因为消费者每隔一段时间会判断是否需要开始重平衡。判断的机制就是消费者定时获取到当前 topic 对应的队列信息和消费者信息,并经过平衡算法,将新分配结果和之前的分配结果进行比较。比如该消费者当前消费的队列是 c1,c2,然而重平衡后是 c1。则会进入执行阶段。

执行阶段就是只拉取最新分配的队列信息。

这样每个消费者都是决策者的思路,简化了重平衡的实现难度。


rocketmq 在实际应用中,由于是阿里出品,所以可以阿里系的产品对接会更方便。比如 rocketmq + canal等。此外,rocketmq 的 tag 特性(对 topic 的进一步拆分),也让 rocketmq 在电商等领域应用广泛。


那么,下一篇,我们会对比学习 rocketmq 和 kafka。



https://www.xamrdz.com/backend/3eh1937491.html

相关文章: