1 为什么需要消息有序
996一辈子了,准备去银行存取款,对应两个异步短信消息,要保证先存后取:
- M1 存钱
- M2 取钱
- 而MQ默认发消息到不同Q显然是行不通的,会乱序。
因此,需发往同一Q,依赖队列的先进先出机制。
2 基本概念
有序消息,又叫顺序消息(FIFO消息),指消息的消费顺序和产生顺序相同。
如订单的生成、付款、发货,这串消息必须按序处理。顺序消息又可分为:
2.1 全局顺序
一个Topic内所有的消息都发布到同一Q,按FIFO顺序进行发布和消费:
适用场景
性能要求不高,所有消息严格按照FIFO进行消息发布和消费的场景。
2.2 分区顺序
对于指定的一个Topic,所有消息按sharding key进行区块(queue)分区,同一Q内的消息严格按FIFO发布和消费。
Sharding key是顺序消息中用来区分不同分区的关键字段,和普通消息的Key完全不同。
性能要求高,根据消息中的sharding key去决定消息发送到哪个queue。
2.3 对比
- 发送方式对比
-
3 如何保证消息顺序?
在MQ模型中,顺序需由3个阶段去保障
- 消息被发送时保持顺序
- 消息被存储时保持和发送的顺序一致
- 消息被消费时保持和存储的顺序一致
4 RocketMQ 有序消息实现原理
RocketMQ消费端有两种类型:
- MQPullConsumer
- MQPushConsumer
底层都是通过pull机制实现,pushConsumer是一种API封装而已。
MQPullConsumer 由用户控制线程,主动从服务端获取消息,每次获取到的是一个MessageQueue中的消息。
PullResult中的 List msgFoundList
MQPushConsumer
由用户注册
MessageListener
来消费消息,在客户端中需要保证调用
MessageListener
时消息的顺序性
看源码
拉取生产端消息
判断是并发的还是有序的,对应不同服务实现类
5 有序消息的缺陷
发送顺序消息无法利用集群的Failover特性,因为不能更换MessageQueue进行重试。
因为发送的路由策略导致的热点问题,可能某一些MessageQueue的数据量特别大
- 消费的并行读依赖于queue数量
- 消费失败时无法跳过