RocketMQ在默认的情况下消息发送会采取Round Robin轮询方式把消息发送到不同的queue(分区队列);
RocketMQ在消费消息的时候从多个queue上拉取消息,这种情况发送和消费是不能保证顺序。
但是如果控制发送的顺序消息只依次发送到同一个queue中,消费的时候只从这个queue上依次拉取,则就保证了顺序。
RocketMQ能严格保证消息的有序性,将顺序消息分为全局顺序消息与分区顺序消息。
- 全局顺序:对于指定的一个 Topic,所有消息按照严格的先入先出(FIFO)的顺序进行发布和消费。
- 分区顺序:对于指定的一个 Topic,所有消息根据hashKey进行区块分区。同一个分区内的消息按照严格的 FIFO 顺序进行发布和消费。
RocketMQ实现消息的有序性,需要从三个方面一起保证消息的有序性:
- 生产者生产顺序消息:
多线程发送的消息无法保证有序性,因此,需要业务方在发送时,针对同一个业务编号(如同一笔订单)的消息需要保证在一个线程内顺序发送,在上一个消息发送成功后,在进行下一个消息的发送。
对应到mq中,消息发送方法就得使用同步发送,异步发送无法保证顺序性
- Broker保存顺序消息:
mq的topic下会存在多个queue,要保证消息的顺序存储,同一个业务编号的消息需要被发送到一个queue中。
对应到mq中,需要使用MessageQueueSelector来选择要发送的queue,即对业务编号进行hash,然后根据队列数量对hash值取余,将消息发送到一个queue中
- 消费者顺序消费消息:RocketMQ消费端默认消费逻辑:
1、负载均衡,指定消费者负责某些队列;
2、当前消费者开启多个线程开始同时消费这个队列,远程拉取消息。从上面消费逻辑可以看到,如果要保证消息有序消费,就要解决这两个问题,需要用到锁来保证一个队列同时只有一个消费者线程进行消费,在broker端,rocketmq是通过锁定MessageQueue的方式,来保证同一时刻,只能有一个消费者进行消费,而在消费端,rocketmq是通过synchronized锁定ConsumeRequest中的run方法,来保证一个消费者同时只能有一个线程进行消费
暂无评论内容