一、消息队列的演进
1、初始阶段
最初的消息队列,就是一个严格意义上的队列。队列是一种数据结构,先进先出,在消息入队出队过程中,保证这些消息严格有序。早期的消息队列就是按照“队列”的数据结构设计的。
队列模型:
生产者(Producer)发消息就是入队操作,消费者(Consumer)收消息就是出队也就是删除操作,服务端存放消息的容器自然就称为“队列”。
- 如果有多个生产者往同一个队列里面发送消息,这个队列中可以消费到的消息,就是这些生产者生产的所有消息的合集。消息的顺序就是这些生产者发送消息的自然顺序。
- 如果有多个消费者接收同一个队列的消息,这些消费者之间实际上是竞争的关系,每个消费者只能收到队列中的一部分消息,也就是说任何一条消息只能被其中的一个消费者收到。
2、发布 - 订阅模型阶段
如果需要将一份消息数据分发给多个消费者,要求每个消费者都能收到全量的消息,例如,对于一份订单数据,风控系统、分析系统、支付系统等都需要接收消息。
这个时候,单个队列就满足不了需求,一个可行的解决方式是,为每个消费者创建一个单独的队列,让生产者发送多份。但是同样的一份消息数据被复制到多个队列中会浪费资源,更重要的是,生产者必须知道有多少个消费者。为每个消费者单独发送一份消息,这实际上违背了消息队列“解耦”这个设计初衷。
为了解决这个问题,演化出了另外一种消息模型:发布 - 订阅模型(Publish-Subscribe Pattern)
消息的发送方称为发布者(Publisher),消息的接收方称为订阅者(Subscriber),服务端存放消息的容器称为主题(Topic)。
- 发布者将消息发送到主题中,订阅者在接收消息之前需要先“订阅主题”。
- 每份订阅中,订阅者都可以接收到主题的所有消息。
3、总结:
- 在很长的一段时间,队列模式和发布 - 订阅模式是并存的。
- 有些消息队列同时支持这两种消息模型,比如 ActiveMQ。
- 对比这两种模型,生产者就是发布者,消费者就是订阅者,队列就是主题,并没有本质的区别。它们最大的区别是:一份消息数据能不能被消费多次的问题。
- 实际上,在这种发布 - 订阅模型中,如果只有一个订阅者,那它和队列模型就基本是一样的了。也就是说,发布 - 订阅模型在功能层面上是可以兼容队列模型的。
二、RabbitMQ 的消息模型