深入消息发送
消息生产者流程
深入消息模式
拉模式
代码上使用
推模式
代码上使用
长轮询
流量控制
消息队列负载与重新分布机制
RocketMQ 默认提供5 中分配算法
如果有8 个消息队列(q1,q2,q3,q4,q5,q6,q7,q8),有3 个消费者(c1,c2,c3)
1) 平均分配(AllocateMessageQueueAveragely)
c1:q1,q2,q3
c2:q4,q5,q6
c3:q7,q8,
2) 平均轮询分配(AllocateMessageQueueAveragelyByCircle)
c1:q1,q4,q7
c2:q2,q5,q8
c3:q3,q6
3) 一直性Hash(AllocateMessageQueueConsistentHash)
不推荐使用,因为消息队列负载均衡信息不容易跟踪
4) 根据配置(AllocateMessageQueueByConfig)
为每一个消费者配置固定的消费队列
5) 根据Broker 部署机房名(AllocateMessageQueueByMachineRoom)
对每一个消费者负载不同Broker 上的队列
消息确认(ACK)
todo
消息ACK 机制
RocketMQ 是以consumer group+queue 为单位是管理消费进度的,以一个consumer offset 标记这个这个消费组在这条queue 上的消费进度。
如果某已存在的消费组出现了新消费实例的时候,依靠这个组的消费进度,就可以判断第一次是从哪里开始拉取的。
每次消息成功后,本地的消费进度会被更新,然后由定时器定时同步到broker,以此持久化消费进度。
但是每次记录消费进度的时候,只会把一批消息中最小的offset 值为消费进度值
todo
消息进度存储
广播模式
同一个消费组的所有消费者都需要消费主题下的所有消息,因为消费者的行为都是独立的,互不影响,固消息进度需要独立存储,所以这种模式下消息进度存储在消费者本地。
todo
集群模式
集群模式消息进度存储文件存放在服务器Broker 上。
顺序消息
顺序消息(FIFO 消息)是消息队列RocketMQ 提供的一种严格按照顺序来发布和消费的消息。顺序发布和顺序消费是指对于指定的一个Topic,生产者按照一定的先后顺序发布消息;消费者按照既定的先后顺序订阅消息,即先发布的消息一定会先被客户端接收到。顺序消息分为全局顺序消息和分区顺序消息。
全局顺序消息
RocketMQ 在默认情况下不保证顺序,要保证全局顺序,需要把Topic 的读写队列数设置为1,然后生产者和消费者的并发设置也是1。所以这样的话高并发,高吞吐量的功能完全用不上。
todo
适用场景
适用于性能要求不高,所有的消息严格按照FIFO( 全称First in, First out,先进先出) 原则来发布和消费的场景。
示例
要确保全局顺序消息,需要先把Topic 的读写队列数设置为1,然后生产者和消费者的并发设置也是1。
mqadmin update Topic -t AllOrder -c DefaultCluster -r 1 -w 1 -n 127.0.0.1:9876 在证券处理中,以人民币兑换美元为Topic,在价格相同的情况下,先出价者优先处理,则可以按照FIFO 的方式发布和消费全局顺序消息。
分区顺序消息
对于指定的一个Topic,所有消息根据Sharding Key 进行区块分区。同一个分区内的消息按照严格的FIFO 顺序进行发布和消费。Sharding Key 是顺序消息中用来区分不同分区的关键字段,和普通消息的Key 是完全不同的概念。
适用场景
适用于性能要求高,以 Sharding Key 作为分区字段,在同一个区块中严格地按照 FIFO 原则进行消息发布和消费的场景。
示例
在控制台创建顺序消息使用的不同类型 Topic 对比如下。
Topic 的消息类型 | 是否支持事务消息 | 是否支持定时/延时消息 | 性能 |
---|---|---|---|
无序消息(普通、事务、定时/延时消息) | 是 | 是 | 最高 |
分区顺序消息 | 否 | 否 | 高 |
全局顺序消息 | 否 | 否 | 一般 |
消息类型 | 是否支持可靠同步发送 | 是否支持可靠异步发送 | 是否支持 Oneway 发送 |
---|---|---|---|
无序消息(普通、事务、定时/延时消息) | 是 | 是 | 是 |
分区顺序消息 | 是 | 否 | 否 |
全局顺序消息 | 是 | 否 | 否 |
使用顺序消息时,请注意以下几点:
延时消息/定时消息
概念介绍
定时消息与延时消息在代码配置上存在一些差异,但是最终达到的效果相同:消息在发送到消息队列 RocketMQ 版服务端后并不会立马投递,而是根据消息中的属性延迟固定时间后才投递给消费者。
适用场景
定时消息和延时消息适用于以下一些场景:
使用方式
定时消息和延时消息的使用在代码编写上存在略微的区别:
注意事项
定时和延时消息的 msg.setStartDeliverTime
参数需要设置成当前时间戳之后的某个时刻(单位毫秒)。如果被设置成当前时间戳之前的某个时刻,消息将立刻投递给消费者。
msg.setStartDeliverTime
参数可设置 40 天内的任何时刻(单位毫秒),超过 40 天消息发送将失败。StartDeliverTime
是服务端开始向消费端投递的时间。 如果消费者当前有消息堆积,那么定时和延时消息会排在堆积消息后面,将不能严格按照配置的时间进行投递。例如,设置定时消息 5 天后才能被消费,如果第 5 天后一直没被消费,那么这条消息将在第 8 天被删除。
消息过滤
概念介绍
RocketMQ 分布式消息队列的消息过滤方式有别于其它MQ 中间件,是可以实现服务端的过滤。
描述消息队列 RocketMQ 版的消费者如何根据 Tag 在消息队列 RocketMQ 版服务端完成消息过滤,以确保消费者最终只消费到其关注的消息类型。
场景示例
以下图电商交易场景为例,从客户下单到收到商品这一过程会生产一系列消息,以以下消息为例:
这些消息会发送到 Trade_Topic Topic 中,被各个不同的系统所订阅,以以下系统为例:
示例代码
发送消息时,每条消息必须指明 Tag:
Message msg = new Message("MQ_TOPIC","TagA","Hello MQ".getBytes());
消费者如需订阅某 Topic 下所有类型的消息,Tag 用符号 * 表示:
consumer.subscribe("MQ_TOPIC", "*", new MessageListener() {
public Action consume(Message message, ConsumeContext context) {
System.out.println(message.getMsgID());
return Action.CommitMessage;
}
});
消费者如需订阅某 Topic 下某一种类型的消息,请明确标明 Tag:
consumer.subscribe("MQ_TOPIC", "TagA", new MessageListener() {
public Action consume(Message message, ConsumeContext context) {
System.out.println(message.getMsgID());
return Action.CommitMessage;
}
});
消费者如需订阅某 Topic 下多种类型的消息,请在多个 Tag 之间用 || 分隔:
consumer.subscribe("MQ_TOPIC", "TagA||TagB", new MessageListener() {
public Action consume(Message message, ConsumeContext context) {
System.out.println(message.getMsgID());
return Action.CommitMessage;
}
});