RabbitMQ,RocketMQ,Kafka消息模型
一.消息模型概述
1.消息队列模型/点对点模型
早期的消息队列是按照”队列”的数据结构来设计的。
生产者(Producer)产生消息,进行入队操作,消费者(Consumer)接收消息,就是出队操作,存在于服务端的消息容器就称为消息队列。
当然消费者也可能不止一个,存在的多个消费者是竞争的关系,消息被其中的一个消费者消费了,其它的消费者就拿不到消息了。
2.发布订阅模型
如果一个人消息想要同时被多个消费者消费,那么上面的队列模式就不适用了,于是又引出了一种新的模式,发布订阅模型。
在发布-订阅模型中,消息的发送方称为发布者(Publisher),消息的接收方称为订阅者(Subscriber),服务端存放消息的容器称为主题(Topic)。
发布者发送消息到主题中,然后订阅者需要先订阅主题。订阅主题的订阅者之后就可以收到发送者发送的消息了。
发布订阅也是兼容消息队列模型的,如果只有一个订阅者,就是消息队列模型了。
二.各个消息队列的消息模型
1.RabbitMQ的消息模型
RabbitMQ 使用的还是消息队列这种消息模型,不过它引入了一个 Exchange 的概念。
注:因为还是使用点对点模型,所以相比于RocketMQ和Kafka,它的消息一般不能被多个消费者消费。
Exchange 也就是交换器,位于生产者和队列之间,生产者产生的数据是直接发送到 Exchange 中,然后 Exchange 根据配置的策略将消息发送到对应的队列中,消息队列中的消息再被消息队列对应的消费者消费,一个消费者只能消费一次。
Publisher:生产者,也就是要发送消息的程序,但是不再发送到队列中,而是发送给交换机
Consumer:消费者,与以前一样,订阅队列,没有变化
Queue:消息队列也与以前一样,接收消息、缓存消息,但是我们需要让消息队列和交换机绑定。
Exchange:交换机。一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。Exchange有以下4种类型:
- Fanout:广播,将消息交给所有绑定到交换机的队列
- Direct:通过routing key直接匹配把消息交给相应的消息队列
- Topic:通过通配符匹配把消息交给相应的消息队列
- Headers:不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中 headers 属性进行匹配。不实用,所以基本不会用。
2.RocketMQ5.0的消息模型
[1]架构图
[2]具体流程
在 Apache RocketMQ 的领域模型中,整体流程如下:
- 消息由生产者初始化并发送到Apache RocketMQ 服务端。
- 消息按照到达Apache RocketMQ 服务端的顺序存储到主题的指定队列中。
- 消费者按照指定的订阅关系从Apache RocketMQ 服务端中获取消息并消费。
[3]基础概念
(1)生成者
生产者和主题的关系为多对多关系,即同一个生产者可以向多个主题发送消息.
发送消息的时候可以设置消息对应的Topic和Tag等属性。
(2)Topic
表示一类消息的集合,每个主题包含若干条消息,每条消息只能属于一个主题,是RocketMQ进行消息订阅的基本单位。
主题内部由多个队列组成,消息的存储和水平扩展能力以及针对主题的所有约束和属性设置最终是由队列实现的。
(3)订阅关系
定义
订阅关系是 Apache RocketMQ 系统中消费者获取消息、处理消息的规则和状态配置。
订阅关系由消费者分组动态注册到服务端系统,并在后续的消息传输中按照订阅关系定义的过滤规则进行消息匹配和消费进度维护。
通过配置订阅关系,可控制如下传输行为:
- 消息过滤规则:用于控制消费者在消费消息时,选择主题内的哪些消息进行消费,设置消费过滤规则可以高效地过滤消费者需要的消息集合,灵活根据不同的业务场景设置不同的消息接收范围。具
- 消费状态:Apache RocketMQ 服务端默认提供订阅关系持久化的能力,即消费者分组在服务端注册订阅关系后,当消费者离线并再次上线后,可以获取离线前的消费进度并继续消费。
订阅关系判断原则
Apache RocketMQ 的订阅关系按照消费者分组和主题粒度设计,因此,一个订阅关系指的是指定某个消费者分组对于某个主题的订阅,判断原则如下:
- 不同消费者分组对于同一个主题的订阅相互独立如下图所示,消费者分组Group A和消费者分组Group B分别以不同的订阅关系订阅了同一个主题Topic A,这两个订阅关系互相独立,可以各自定义,不受影响。
同一个消费者分组对于不同主题的订阅也相互独立如下图所示,消费者分组Group A订阅了两个主题Topic A和Topic B,对于Group A中的消费者来说,订阅的Topic A为一个订阅关系,订阅的Topic B为另外一个订阅关系,且这两个订阅关系互相独立,可以各自定义,不受影响。
(4)消费者
消息消费的角色。
- 支持以推(push),拉(pull)两种模式对消息进行消费。
- 同时也支持集群方式和广播方式的消费。
- 提供实时消息订阅机制,可以满足大多数用户的需求。
1 |
|
(5)消费者组
消费者分组是 Apache RocketMQ 系统中承载多个消费行为一致的消费者的负载均衡分组。
和消费者不同,消费者分组并不是运行实体,而是一个逻辑资源。在 Apache RocketMQ 中,通过消费者分组内初始化多个消费者实现消费性能的水平扩展以及高可用容灾。
在消费者分组中,统一定义以下消费行为,同一分组下的多个消费者将按照分组内统一的消费行为和负载均衡策略消费消息。
- 订阅关系:Apache RocketMQ 以消费者分组的粒度管理订阅关系,实现订阅关系的管理和追溯。
- 投递顺序性:Apache RocketMQ 的服务端将消息投递给消费者消费时,支持顺序投递和并发投递,投递方式在消费者分组中统一配置。
- 消费重试策略: 消费者消费消息失败时的重试策略,包括重试次数、死信队列设置等。
3.Kafka的消息模型
[1]架构图
[2]基础概念
- Broker:Broker主要负责消息的存储、投递和查询以及服务高可用保证。可以将Broker理解为kafka的一个实例。
- Topic:消息的主题,在每个 broker 上都可以创建多个 topic 。
- Partition:Topic的分区,每个 topic 可以有多个分区,分区的作用是做负载,提高 kafka 的吞吐量。同一个 topic 在不同的分区的数据是不重复的,partition 的表现形式就是一个一个的文件夹。
- Offset:每个消费者在消费时都会维护自己的Offset,Offset是一个消费位移标记,用于跟踪消费者在特定分区中的读取位置。它标识了消费者已经处理了到达的消息的位置,使得Kafka可以从正确的地方继续消费。 具体的Offset存放在Zookeeper中。
- Consumer Group:可以将多个消费组构成一个消费者组。 一个分区的每条消息在一个消费者组里只能被一个消费者所消费,组内不可以重复消费。 *但是如果有不同消费者组同时订阅了这个消息,则这个消息会被不同的消费者重复消费。*
- Zookeeper/Raft:kafka 2.8 版本之前是依赖 zookeeper 来保存集群的的元信息,来保证系统的可用性。kafka 2.8 版本之后就根据raft来保证系统的可用性。
[3]具体流程
Kafka投递消息流程:
- 生产者发送消息:生产者将消息发送到Kafka集群,并指定目标主题(topic)。
- 选择分区:生产者根据定义的分区策略选择一个目标分区(partition)。如果没有指定键,使用轮询或其他策略来选择分区。
Kafka选择分区的策略主要有:轮询,键值(根据消息的Key),或自定义分区策略。
- 消息写入:生产者将消息发送到指定的分区。Kafka的Broker接收消息,并将其追加到该分区的日志文件中。
- 确认消息:生产者接收Broker的确认(acknowledgment),以确保消息已成功写入。确认级别可以配置(如只需一个副本确认、所有副本确认等)。
Kafka消费消息流程:
- 消费者拉取消息:消费者从Kafka集群中拉取消息。消费者首先会从指定的主题(topic)和分区(partition) 中请求消息。
- 读取偏移量:消费者根据当前的偏移量(offset)读取消息。消费者组的协调者跟踪每个消费者的偏移量。
- 处理消息:消费者处理接收到的消息,通常进行业务逻辑处理。
- 提交偏移量:消费者在处理完消息后,会提交新的偏移量(自动或手动),以记录处理进度。提交的偏移量存储在Kafka的内部主题
__consumer_offsets
中。 - 消息确认:提交偏移量表示消息已成功处理。消费者组的协调者会更新偏移量记录,以便消费者可以从正确的位置继续消费。
3.RocketMQ4.x的消息模型
RocketMQ4.x的大致消息模型和Kafka差不多,就是将分区换成队列。
当然具体实现和部分细节肯定是不同的。