消息模型:主题和队列区别
早期的消息队列,就是按照“队列”的数据结构来设计的。我们一起看下这个图,生产者(Producer)发消息就是入队操作,消费者(Consumer)收消息就是出队也就是删除操作,服务端存放消息的容器自然就称为“队列”。
以下是最初的一种消息模型:队列模型

这种模型中,消费者之间是竞争关系,每个消息只能被一个消费者消费。
但是如果想要一个消息被多个消费者消费,比如说对于一个订单消息,风控系统,分析系统,支付系统都需要得到该订单的信息,那么采用这种模型的话就需要为每一个消费者创建一个队列,但是这样做就需要提前知道有多少个消费者,违背了解耦。
为了解决这个问题,演化出了另外一种消息模型:“发布 - 订阅模型(Publish-Subscribe Pattern)”。

以上两种模型的区别就是,一份消息数据能不能被消费多次的问题。
RabbitMQ 的消息模型
rabbitmq采用队列模型,它用了一个交换机来解决多个消费者消费同一条消息的问题。
生产者不关心消息发送给哪个消费者,它只需要发送给交换机,由交换机决定发送给哪个消费者。

RocketMQ 的消息模型
RocketMQ 使用的消息模型是标准的发布 - 订阅模型。但是它也有队列的概念。
几乎所有的消息队列都采用请求-确认机制,即生产者将消息发送给服务端,服务端收到并写入队列后,会给生产者发送确认响应。而消费端,消费者收到消息并处理完后,也会给服务端发送消息,服务端在收到确认消息后,才会判定消息被消费成功。上面两种,如果没收到确认消息,会重试。
但是这样也存在一个问题,即还没收到一个消息的确认信息时,只能等待,而不能去执行第二条消息,这样是为了保证消息的顺序性。
为了解决这个问题,RocketMQ引入了队列的概念。
每个主题包含多个队列,通过多个队列来实现多实例并行生产和消费。RocketMQ 只在队列上保证消息的有序性,主题层面是无法保证消息的严格顺序的。
RocketMQ 中,订阅者的概念是通过消费组(Consumer Group)来体现的。每个消费组都消费主题中一份完整的消息,不同消费组之间消费进度彼此不受影响,也就是说,一条消息被 Consumer Group1 消费过,也会再给 Consumer Group2 消费。
一个消费组中的消费者是竞争关系,一条消息只会被消费组中的一个消费者消费。
由于每一条消息需要被多个消费组消费,所以消费完的消息并不会立即被删除,这就需要 RocketMQ 为每个消费组在每个队列上维护一个消费位置(Consumer Offset),这个位置之前的消息都被消费过,之后的消息都没有被消费过,每成功消费一条消息,消费位置就加一。
参考
《消息队列高手课》