顺序消费
Table of Contents generated with DocToc (opens new window)
# 三个阶段
- 消息被发送时保持顺序(producer端)
提示
Producer端确保消息顺序,唯一要做的事情就是将消息路由到特定的分区,在RocketMQ中,通过MessageQueueSelector实现分区的选择
MessageQueueSelector messageQueueSelector = new MessageQueueSelector(){
@Override
public MessageQueue select(List<MessageQueue> mqs,Message msg,Object arg){
int select = arg.hashCode();
select = select > 0 ? select : 0;
return mqs.get(select % mqs.size());
}
}
2
3
4
5
6
7
8
- 消息被存储时,保持和发送的顺序一致
提示
这个由mq内部保证一致
- 消息被消费时,保持和存储的顺序一致(consumer端)
# 解决方案
# RabbitMQ
提示
拆分为多个queue,每个queue对应一个consumer,消费者在消费的时候不去直接消费消息,而是将消息保存到内存队列(数组)中,根据消息的关键值(例如订单ID)进行哈希操作,将关键值相同的消息(一组需要保证顺序的消息)发送到相同的内存队列中去,然后分发给底层的Thread处理,一个线程只去一个内存队列中取消息,这样就保证了顺序性(可以支持高并发)。
实际中consumer的数量是受限的,不会仅仅因为消息消费太慢而去增加consumer实例的数量,所以通过这种方式,可以在不增加consumer实例数量的前提下,加快消息消费的速度。
# RocketMQ
生产者消费者一般需要保证顺序消息的话,可能就是一个业务场景下的,比如订单的创建、支付、发货、收货。
这些流程都有一个相同的订单号,可以利用这个订单号来实现顺序消费
一个topic下有多个队列,为了保证发送有序,RocketMQ提供了MessageQueueSelector队列选择机制,他有三种实现:
我们可使用Hash取模法,让同一个订单发送到同一个队列中,再使用同步发送,只有同个订单的创建消息发送成功,再发送支付消息。这样,我们保证了发送有序。
RocketMQ的topic内的队列机制,可以保证存储满足FIFO,剩下的只需要消费者顺序消费即可。
RocketMQ仅保证顺序发送,顺序消费由消费者业务保证!!!
这里很好理解,一个订单发送的时候放到一个队列里面去,同一个的订单号Hash一下是一样的结果,消费的时候肯定是同一个消费者消费,顺序就可以保证了