rocketmq顺序消费

使用消息队列的一个优点就是可以并发的产生和消费消息,提高的系统并发处理的能力,但是也会因此引发消息乱序消费的问题,什么是乱序消费,就是消息的消费顺序,和他们被加入到消息队列的先后顺序是不一样的,那么为什么会发生这样的情况呢,下面我们举一个例子。

加入现在一个producer向mq中添加了两条消息,消息a和消息b,并且是在消息a被成功发送之后,才发送消息b,保证消息a是在消息b之前被加入到消息队列的,但是这个时候,由于客户端的负载均衡策略,消息a被添加到了队列1中,消息b被添加到队里2中,这个时候,有两个consumer在采用集群消费的模式消费消息,又由于消费端的负载均衡策略,consumer1消费队列1,consumer2消费队列2,这里需要注意是,一个队列,同时只能被同一个组中的某一个consumer消费,不存在同组中多个consumer同时消费同一个队列的情况,那么这个时候,由于是两个线程,并行在消费,可能就会是consumer2先消费到队列2中的消息b,然后consumer1才消费到队列1中的消息a,跟消息加入到消息队列中的顺序是不一致的。

如果要保证全局的顺序消息,需要把对应的topic的队列数量设置成1,这样可以保证先放进去的消息,肯定是会被先取出来,同时消费端要使用单线程消费,注意这里说的是单线程消费,而不是单consumer消费,上面说过,一个队列同时只能被一个consumer消费,也就是说,当队列数量是1的时候,就算设置了多个consumer,那么也是没有意义的,因为在某一时候,肯定是只有一个consumer在工作,其他的consumer因为没有多余的队列,只能闲着,那么是不是使用了单个consumer就可以了呢,也不是,加入这个consumer在获取到消息之后,就把消息封装一个,扔到线程池中,仍然是不能保证消息是顺序执行的,这个就不解释了,大家应该自己可以理解,所以要保证全局的顺序消息,队列数量设置成1,单线程消费,两者缺一不可。但是如果真的这样做,那么可想而知,效率是非常低的。

一般情况下,我们并不需要保证全局的消息顺序性,只要保证局部的消息顺序性就可以了,比如某个订单的生成,付款,发货,这三步是必须保证顺序的,但是不同的订单之间,就算发生了乱序,也是没有关系的,并不会产生影响,只要每个订单的付款,发生在该订单的生成之后,该订单的发货,发生在该订单的付款之后就可以了,这个时候,就可以通过使用rocketmq提供的顺序生产和顺序消费的能力来实现,首先我们看一下producer的代码

int orderId = 1;
for(int i = 0; i < 100; ++i){
    Message message = new Message("topic", "tag", ("订单消息体, 订单的id是:" + orderId++).getBytes());
    SendResult sendResult = producer.send(message, new MessageQueueSelector() {
        @Override
        public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
            int id = (int) o;
            int queueNum = list.size();
            //根据订单id,模上消息队列的数量,这样就能保证同一个订单的所有消息,都发送到同一个消息队列中,同时也能将消息均匀的分散到各个队列中
            return list.get(id % queueNum);
        }
    }, orderId);
}

使用自定义的MessageQueueSelector,根据某一特征(例如orderId)来决定将消息发送到哪一个队列。下面再来看看consumer的代码

consumer.registerMessageListener(new MessageListenerOrderly() {
    @Override
    public ConsumeOrderlyStatus consumeMessage(List<MessageExt> list, ConsumeOrderlyContext consumeOrderlyContext) {
        for(MessageExt messageExt : list){
            //业务处理逻辑
        }
        return ConsumeOrderlyStatus.SUCCESS;
    }
});

consumer使用的监听着是MessageListenerOrderly类,与这个类对应的是MessageListenerConcurrently,一个是顺序消费,一个是并发消费,使用顺序消费的时候,每个consumer在拉取对应messageQueue的消息的时候,都要实现获取对应的锁,保证了同一个consumerQueue的消息不能被并发消费,但是不同的consumerQueue的消息可以并发消费,保证了效率。

这就是使用rocketmq进行顺序消费的正确方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值