RabbitMQ学习总结(三)——消息分发,限流与幂等性问题

本文详细探讨了RabbitMQ消费端的核心机制,包括消息确认(ACK)、公平分发、消费端限流及幂等性问题解决方案。通过手动确认、prefetchCount参数和唯一ID+指纹码机制,确保消息处理的准确性和效率。

RabbitMQ学习总结

在上一张讲完了生产端的问题,这一章来讨论一下消费端的问题,首先第一个问题就是MQ如何确认消息被消费端成功接收。

一. 消费端ACK确认

为了保证消息被消费端成功接收,RabbitMQ在将消息发送给消费者之后,会要求消费者在收到消息后返回一个ACK确认,而RabbitMQ在收到该ACK确认后,知道消费端已经成功接收到了该消息,从而安全地将该消息从队列中删除。

另外,当消费端收到消息后,也可以返回NACK,并设置消息重回队列,即将该消息重新放到消息队列队尾(不过一般不会设置重回队列,因为第一次消费不成功的消息,后面一般也不会消费成功,不如直接在消费端记录该异常,而不是让消息重新回到队列中)

在原生的RabbitMQ中有autoAck这一参数,当设置为true时,消费端受到消息会自动的返回ACK,当设置为false时,需要手动地去确认basicAck()

但是在Springboot中,默认会关闭自动Ack(为了实现公平分发),且消息的ACK会由框架自动完成

但是在实际工作中,会希望消息的确认由程序员编程完成,而不是由框架自动确认(防止传来的消息太多消费端来不及处理)

那么可以在配置文件中作如下配置,将消息ACK改为手动实现

spring:
  rabbitmq:
    listener:
      simple:
        acknowledge-mode: manual

然后在消费者者端手动ACK

@RabbitListener(queues = "queue.news")
    public void receive(Book book, Channel channel, @Headers Map<String,Object> heads) throws IOException {
        log.info("收到消息{}",book);
        # do something....
        channel.basicAck((Long)heads.get(AmqpHeaders.DELIVERY_TAG),false);  //如果忽略这一句则消息不会从消息队列中被删除
    }

二. 消息分发机制

RabbitMQ有下面两种分发机制:

  1. Round-robin dispatch(轮询分发)
    RabbitMQ不考虑消息者处理消息的能力,即使其中有的消费者闲置有的消费者高负荷。RabbitMQ会逐个发送消息到在序列中的下一个消费者(而不考虑每个任务的时长等等,且是提前一次性分配,并非一个一个分配)。平均每个消费者获得相同数量的消息.
  2. Fair dispatch (公平分发)
    RabbitMQ根据消费者的处理能力来进行分发处理的。

公平分发主要由prefetchCount 这一参数来实现的。其意思是Consumer在同一个时间点最多处理规定的数量级个数的Message。也就是说,在接收到该Consumer的ack前,它不会将新的Message分发给它。 如prefetchCount=1,则在同一时间下,每个Consumer在同一个时间点最多处理1个Message,同时在收到Consumer的ack前,它不会将新的Message分发给它。

而当prefetchCount设为0时,会采用轮询分发

三. 消费端限流

根据上面的公平分发这一特性,可以完成消费端的限流功能(削峰)

只需打开 acknowledge-mode: manual
然后设置 prefetchCount=1

消费端就可以从消息队列中一条一条的取消息,处理完一条消息后,进行手动确认,然后继续处理下一条消息。而不是消费端一打开,就会有大量的消息发送给消费端,导致服务瘫痪

四.消费端幂等信问题

上一章提到了,为了保证生产端的可靠性投递,没有收到Confirm确认的消息,可能会进行重新投递。 那么就有可能发生Confirm确认由于网络波动问题丢失,重新发送消息后导致消息队列中有两条重复的消息这样的消息存在。如果在消费端不做处理,就有可能将这一条消息重复消费两次。 细想一下,如果该消息涉及大笔的金额,导致转账转了两次,引起的后果是非常可怕的。

解决的方法就是采用唯一ID+指纹码的机制:
在消费端前设置一层服务,在消息被消费前,先进行数据的入库,由于每条消息都有唯一的ID+指纹码,因此可以根据数据库的主键进行去重。如果发现数据库中已经存在该消息,代表其已经被消费过,那么就不会对该消息进行重复消费。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值