- 概述rocket mq
消息中间件是基于队列与消息传递技术,在网络环境中为应用系统提供同步或异步、可靠的消息传输的支撑性软件系统 , RocketMQ是阿里云基于 Apache RocketMQ 构建的低延迟、高并发、高可用、高可靠的分布式消息中间件,今天了解下它。
- rocket mq中间件的架构图
- rocket mq基本组件概念
RocketMQ主要由 Producer、Broker、Consumer 、Nameserver四部分组成,其中Producer 负责生产消息,Consumer 负责消费消息,Broker 负责存储消息,Nameserve负责协调管理前三者,它管理两部分数据:集群的Topic-Queue的路由配置;Broker的实时配置信息。其它模块通过Nameserve提供的接口获取最新的Topic配置和路由信息。
Rocketmq的一些名词解释
主题(Topic)
表示一类消息的集合,每个主题包含若干条消息,每条消息只能属于一个主题,是RocketMQ进行消息订阅的基本单位。
代理服务器(Broker Server)
消息中转角色,负责存储消息、转发消息。代理服务器在RocketMQ系统中负责接收从生产者发送来的消息并存储、同时为消费者的拉取请求作准备。代理服务器也存储消息相关的元数据,包括消费者组、消费进度偏移和主题和队列消息等。
名字服务(Name Server)
名称服务充当路由消息的提供者。生产者或消费者能够通过名字服务查找各主题相应的Broker IP列表。多个Namesrv实例组成集群,但相互独立,没有信息交换。
拉取式消费(Pull Consumer)
Consumer消费的一种类型,应用通常主动调用Consumer的拉消息方法从Broker服务器拉消息、主动权由应用控制。一旦获取了批量消息,应用就会启动消费过程。
推动式消费(Push Consumer)
Consumer消费的一种类型,该模式下Broker收到数据后会主动推送给消费端,该消费模式一般实时性较高。
生产者组(Producer Group)
同一类Producer的集合,这类Producer发送同一类消息且发送逻辑一致。如果发送的是事物消息且原始生产者在发送之后崩溃,则Broker服务器会联系同一生产者组的其他生产者实例以提交或回溯消费。
消费者组(Consumer Group)
同一类Consumer的集合,这类Consumer通常消费同一类消息且消费逻辑一致。消费者组使得在消息消费方面,实现负载均衡和容错的目标变得非常容易。要注意的是,消费者组的消费者实例必须订阅完全相同的Topic。RocketMQ 支持两种消息模式:集群消费(Clustering)和广播消费(Broadcasting)。
集群消费(Clustering)
集群消费模式下,相同Consumer Group的每个Consumer实例平均分摊消息。
广播消费(Broadcasting)
广播消费模式下,相同Consumer Group的每个Consumer实例都接收全量的消息。
普通顺序消息(Normal Ordered Message)
普通顺序消费模式下,消费者通过同一个消费队列收到的消息是有顺序的,不同消息队列收到的消息则可能是无顺序的。
严格顺序消息(Strictly Ordered Message)
严格顺序消息模式下,消费者收到的所有消息均是有顺序的。
代理服务器(Broker Server)
消息中转角色,负责存储消息、转发消息。代理服务器在RocketMQ系统中负责接收从生产者发送来的消息并存储、同时为消费者的拉取请求作准备。代理服务器也存储消息相关的元数据,包括消费者组、消费进度偏移和主题和队列消息等。
消息(Message)
消息系统所传输信息的物理载体,生产和消费数据的最小单位,每条消息必须属于一个主题。RocketMQ中每个消息拥有唯一的Message ID,且可以携带具有业务标识的Key。系统提供了通过Message ID和Key查询消息的功能。
标签(Tag)
为消息设置的标志,用于同一主题下区分不同类型的消息。来自同一业务单元的消息,可以根据不同业务目的在同一主题下设置不同标签。标签能够有效地保持代码的清晰度和连贯性,并优化RocketMQ提供的查询系统。消费者可以根据Tag实现对不同子主题的不同消费逻辑,实现更好的扩展性。
- 使用rocket mq核心流程
- 启动Nameserver
- Broker都注册到Nameserver上
- Producer从Nameserver上获取发消息的topic信息
- Producer发消息
- Producer向提供服务的所有master建立长连接,且定时向master发送心跳
- Consumer通过NameServer集群获得Topic的路由信息
- Consumer会与所有的Master和所有的Slave都建立连接进行监听新消息
- Consumer接听消息
- 使用rocket代码示例
引入依赖
Application.yaml添加配置
server:
port: 8082
rocketmq:
name-server: 127.0.0.1:9876
producer:
group: my-producer-group
logging:
file:
path: /usr/log/mqproductservice/mqproductservice.log
level:
root: INFO
com.anran.projectmanage.mapper: DEBUG
spring:
cloud:
stream:
bindings:
output: { destination: test-topic,content-type: application/json }
rocketmq:
binder:
name-server: 127.0.0.1:9876
定义消息生产者类,并且注入rocketmq-client-starter包里面的JMQTemplate类,该类定义好了生产者发送消息的方法
定义消息消费者类并且实现JMQListener,引入的rocketmq-client-starter包里面有获取在application.yaml配置的需要监听的消费者topc主题的配置类rocketMQProperties,通过消费者类里面的getTopic()能监听改top主题需要消费的消息,消费消息的逻辑则在消费者类 onMessage()的方法中。
- Rocketmq的消息生产者与消费者
生产者和消费者是消息队列的两个重要角色,生产者向消息队列写入数据,消费者从消息对立读取数据,RockketMQ的大部分用户只需要和生产者、消费者打交道,现在来了解下他们的特点已经它们相关的offet和log。
rocketMQ的消息模型
一个Topic(消息主题)可能对应多个实际的消息队列(MessgeQueue)
在底层实现上,为了提高MQ的可用性和灵活性,一个Topic在实际存储的过程中,采用了多队列的方式,具体形式如上图所示。每个消息队列在使用中应当保证先入先出(FIFO,First In First Out)的方式进行消费。 那么,基于这种模型,就会引申出两个问题:
- 生产者 在发送相同Topic的消息时,消息体应当被放置到哪一个消息队列(MessageQueue)中?
- 消费者 在消费消息时,应当从哪些消息队列中拉取消息?
消息的系统间传递时,会跨越不同的网络载体,这会导致消息的传播无法保证其有序。
深入了解下MQ的消息投递机制
我们先来看看生产者(producer)的投递消息策略
- 默认的投递方式:基于queue队列的轮训算法投递
默认情况下,采用了最简单的轮训算法,这种算法有个很好的特性就是,保证每一个queue的消息投递数量尽肯能均匀,
- 默认投递方式的增强:基于queue队列轮训算法和消息投递延迟最小的策略投递
默认的投递方式比较简单,但是也暴露了一个问题,就是有些queue队列可能由于自身数量挤压等原因,可能在投递的过程比较长,对于这样的queue队列会影响后续投递的效果。
基于这种现象,rocketMQ在每发送一个MQ消息后,都会统计一下消息投递的时间延迟,根据这个时间延迟,可以知道往哪个queue队列的投递的速度快
在这种场景,会优先使用消息投递延迟最小的策略,如果没有生效再使用queue队列轮训的方式。
- 顺序消息的投递方式
上述的两种投递方式属于对消息投递的时序性没有要求的场景,这种投递的速度和效率比较高。但是在有些场景下,需要保证同类型消息投递和消费的顺序性。
例如,假设现在有TOPIC-TOPIC_SALE_ORDER,该topic下有4个queue队列,该topic用与传递订单的状态变迁,未支付、已支付、发货中(处理中)、发货成功、发货失败。
在时序上,生产者从时序上可以生产如下几个消息:
订单T0000001:未支付 –->订单T0000001:已支付 –->
订单T0000001:发货中(处理中) –->订单T0000001:发货失败,这种情况下我们希望消费者消费消息和我们发送的一致。
如下图
RocketMQ在生产者消息投递的过程中,使用了MessageQueueSelector作为队列选择的策略接口,其定义如下:
相应的,目前rocketMQ也提供了如下几种实现:
默认实现:
投递策略 | 策略实现类 | 说明 |
随机分配策略 | SelectMessageQueueByRandom | 使用了简单的随机数选择算法 |
基于Hash分配策略 | SelectMessageQueueByHash | 根据附加参数的Hash值,按照消息 队列列表的大小取余数,得到消息队列 的index |
基于机器机房位置分配策略 | SelectMessageQueueByMachineRoom | 开源的版本没有具体的实现, 基本的目的应该是机器的就近原则分配 |
既然说了消息的投递queue策略,那么也来了解下rocketMQ消费者分配queue队列
RocketMQ对于消费者消费消息有两种形式:
- BROADCASTING:广播式消费,这种模式下,一个消息会被通知到每一个消费者
- CLUSTERING: 集群式消费,这种模式下,一个消息最多只会被投递到一个消费者上进行消费