写点什么

RocketMQ 消息模型

用户头像
废材姑娘
关注
发布于: 2021 年 01 月 04 日
RocketMQ消息模型

开篇

不知道大家跟我是不是有同样的困惑, 在学习不同的消息框架时都会接触到主题, 队列, 分区, 生产者, 消费者等等一些概念. 有时会觉得很抽象, 他们之间到底时如何配合工作, 完成消息的发送和消费的过程的.

今天我们就通过学习消费模型来了解下这些概念. 从而搞清楚他们到底是如何工作的.

消息模型

现在流行的有两种消息模型: 队列模型和发布-订阅模型, 二者之间有什么关系呢? 相信大家能够猜到, 发布-订阅模型是从队列模型演进而来, 为什么会这样演进, 解决了什么问题呢? 接下来让我们一起学习一下.


队列模型

队列模型顾名思义, 就是根据队列这种数据结构来设计的, 结构如下图所示:


Screen Shot 2021-01-04 at 11.15.29 PM.png


生产者发送消息到消费队列的尾部, 消费者从消费队列前获取消息进行消费. 队列模型很简单, 但是这个结构有一个问题就是, 当有多个消费者的时候, 他们之间是竞争关系, 也就意味着每个消费者只能消费到部分消息, 并不是全量消息.

有人会说,我们可以有多个对立呀, 让生产者写多个队列, 每个消费者消费一个队列. 这种方案可以解决问题, 但是很浪费资源呀. 如果消费者多了, 我得重复多少份消息呀. 为了解决这个问题, 演化出了发布-订阅模型.

发布-订阅模型

发布订阅模型的结构如下图所示:

在发布 - 订阅模型中,消息的发送方称为发布者(Publisher),消息的接收方称为订阅者(Subscriber),服务端存放消息的容器称为主题(Topic)。发布者将消息发送到主题中,订阅者在接收消息之前需要先“订阅主题”。“订阅”在这里既是一个动作,同时还可以认为是主题在消费时的一个逻辑副本,每份订阅中,订阅者都可以接收到主题的所有消息。


Screen Shot 2021-01-04 at 11.24.12 PM.png


在发布 - 订阅模型中,消息的发送方称为发布者(Publisher),消息的接收方称为订阅者(Subscriber),服务端存放消息的容器称为主题(Topic)。发布者将消息发送到主题中,订阅者在接收消息之前需要先“订阅主题”。“订阅”在这里既是一个动作,同时还可以认为是主题在消费时的一个逻辑副本,每份订阅中,订阅者都可以接收到主题的所有消息。

这里我们可以发现, 队列模型和发布-订阅模型最大的区别就是,一份消息数据能不能被消费多次的问题。


RocketMQ 的消息模型

学习了两种消息模型之后, 让我们来学习一下 RocketMQ 的消息模型. 为了便于后面的讲解, 我先把 RocketMQ 消息模型的结构图放在下面. 这是一个标准的发布-订阅模型. 但是不知道大家发现没有, 除了上文我们介绍的发布-订阅模型中的生成者, 消费者, 主题的概念之外. RocketMQ 的消息模型中又多了一个队列的概念. 这个队列是干什么的呢? 为什么需要一个队列, 他和主题又有什么关系呢? 


别着急, 我们一点点来分析, 要解答这个问题, 我们需要从消息队列的消费机制----请求-确认机制开始说起

请求-确认机制

请求-确认机制主要是用来保证消息不会丢失. 对于生产者来说,将消息发送给 Broker, Broker 在收到消息并将消息写入主题或者队列中后,会给生产者发送确认响应。如果生产者没有收到确认或者收到失败的响应,则会重新发送消息。对于消费者来说,在收到消息并完成自己的消费业务逻辑后,也会给服务端发送消费成功的确认。

引入请求-确认机制之后,消费端在消费消息时就会收到限制,为了确保消息的有序性,在某一条消息被成功消费之前,下一条消息是不能被消费的,否则就会破坏有序性。这就决定了一个主题同时只能有一个消费者在进行消费。 这对于一个伟大的中间件来说怎么可能呢, 不能并行消费是绝对不能容忍的, 于是 RocketMQ 在主题的基础上又引入了队列的概念,每个主题下面可以包含多个队列, 通过多队列来实现多实例并行生产和消费。RocketMQ 的消息模型大致如下图所示:


Screen Shot 2020-12-29 at 8.48.56 AM.png


图中的主题(Topic),队列(Queue), 消费者(Consumer),生产者(Producer)大家都已经熟悉了, 但是图中的消费组(Consumer Group)和生产组(Producer Group)又是什么呢?

RocketMQ 中,消费组相当于订阅者,订阅 Topic 是以一个消费组来订阅的,发送到 Topic 的消息,只会被订阅此 Topic 的每个 group 中的一个 consumer 消费。 一个消费组中可以包含多个消费者, 不同的消费组之间是互相不受影响的,也就是说一条消息,消费组 1 消费过了, 也会被消费组 2 消费。也就是说, 一个 队列(Queue),只能被消费组里的一个消费者消费,但是可以同时被多个消费组消费,消费组里的每个消费者是关联到一个 Queue 的,因此有这样的说法:对于一个 topic,同一个 group 中的消费者个数和队列个数最好一致, 这样能得到充分的使用, 也不会浪费资源.


既然多个消费组都可以消费同一条消息. 那你可能会好奇我们有怎么记住每一个消费组消费到哪条消息了呢?首先为了保证消息被多个消费组消费,一个消费组消消费完消息后一定不会删除,在 RocketMQ 中使用的是消费位置(offset)记录每个消费组在每个队列上消费到哪一条消息。每消费一条消息消费位置就会加 1. 当所有订阅该该主题的所有消费者组都消费了这条消息以后, 才能删除这条消息。

生产组则是发布者, 一个生产组中可以有多个生产者。生产者在生产消息时可以在采用随机, 轮询, 哈希等方式向任何队列发送消息。


好了, RocketMQ 的消息模型我们就介绍到这里了, 顺着这个消息模型, 大家是不是也产生了很多的疑问呢?引入了并行消费的方案,如何保证消息的有序性呢?除了请求-确认机制保证消息的可靠性之外还有什么机制呢?

如果消费者消费的太慢, 导致消息积压要怎么处理呢?



发布于: 2021 年 01 月 04 日阅读数: 45
用户头像

废材姑娘

关注

废材姑娘 2018.01.24 加入

大家叫我双儿,梦想着成为韦小宝的老婆 欢迎关注我的个人公众号----废材姑娘,回复“双儿”加我微信,让我们一起探索多彩的世界。

评论

发布
暂无评论
RocketMQ消息模型