rocketmq怎么保证队列完全顺序消费

原文:https://www.zhihu.com/question/30195969

实际上,RocketMQ是支持顺序消费的。

但这个顺序,不是全局顺序,只是分区顺序。要全局顺序只能一个分区。

之所以出现你这个场景看起来不是顺序的,是因为发送消息的时候,消息发送默认是会采用轮询的方式发送到不通的queue(分区)。如图:



而消费端消费的时候,是会分配到多个queue的,多个queue是同时拉取提交消费。

如图:




但是同一条queue里面,RocketMQ的确是能保证FIFO的。那么要做到顺序消息,应该怎么实现呢——把消息确保投递到同一条queue。

rocketmq消息生产端示例代码如下:



按照这个示例,把订单号取了做了一个取模运算再丢到selector中,selector保证同一个模的都会投递到同一条queue。

即: 相同订单号的--->有相同的模--->有相同的queue。

最后就会类似这样:



这样同一批你需要做到顺序消费的肯定会投递到同一个queue,同一个queue肯定会投递到同一个消费实例,同一个消费实例肯定是顺序拉取并顺序提交线程池的,只要保证消费端顺序消费,则大功告成!

如何保证顺序消费? 如果是使用MessageListenerOrderly则自带此实现,如果是使用MessageListenerConcurrently,则需要把线程池改为单线程模式。

(这里假设触发了重排导致queue分配给了别人也没关系,由于queue的消息永远是FIFO,最多只是已经消费的消息重复而已,queue内顺序还是能保证)

但的确会有一些异常场景会导致乱序。如master宕机,导致写入队列的数量上出现变化。

如果还是沿用取模的seletor,就会一批订单号的消息前面散列到q0,后面的可能散到q1,这样就不能保证顺序了。除非选择牺牲failover特性,如master挂了无法发通接下来那批消息。

从消费端,如果想保证这批消息是M1消费完成再消费M2的话,可以使用MessageListenerOrderly接口,但是这样的话会有以下问题:

1. 遇到消息失败的消息,无法跳过,当前队列消费暂停2. 目前版本的RocketMQ的MessageListenerOrderly是不能从slave消费消息的。


更多分析请参考:

RocketMQ--角色与术语详解 - 薛定谔的风口猪

RocketMQ--水平扩展及负载均衡详解 - 薛定谔的风口猪


猜你喜欢

转载自blog.csdn.net/notOnlyRush/article/details/80331329
今日推荐