RabbitMQ高级特性(RabbitMQ学习笔记 3)

一、如何保障消息100%投递成功?

1.1 消息生产者的如何做到可靠性投递?

消息的生产者想要确保消息成功发出并且被接收需要做到以下四个方面:

  1. 保障消息的成功发出
  2. 保障MQ节点的成功接收
  3. 发送端收到MQ节点(Broker)确认应答 完
  4. 善的消息进行补偿机制

解决方案:

  1. 消息消息落库,对消息的状态进行打标
    这种方法是将消息持久化到数据库中,并设置一个字段对消息的状态进行标识(如发送中、发送成功、发送失败)。然后遍历所有消息对于发送失败的消息重新发送,同时设置一定的重试次数限制,达到限制就不再重试。(注意一定是先将消息持久化到数据库再发送消息)

  2. 消息延迟投递,做二次确认回调检查
    生成端生成一条消息发送到MQ,同时发送一条延迟的消息(如延迟3分钟发送),消费端消费成功这条消息之后,会发送一条消息确认已经消费完成。此时Callback服务监听消费端发出的消息,然后将消息持久化到数据库中。当延迟投递的消息发送到MQ,Callback服务监听到延迟发送的消息,并根据库所存储的消息的状态进行判断,判断消息是否正常的走完了所有的流程。如果确认成功那就结束,如果存在问题那么就会发送Resend Command到消息生产端要求重新发送消息。
    在这里插入图片描述

二、幂等性

简单来说幂等性就是在高并发操作时,不会发生混乱。如电影院售票总共有一百张票,当100个人同时买票时,每个线程都要对票的总数减1,所谓混乱就是每个线程都是查询到总票数为100然后减1,这样所有线程操作完剩余的票数就是99,这显然是不对的。幂等性保障就是为了避免这种情况的发生,最后剩余票数为0才是我们想要的结果。

2.1 消息消费端的幂等性保障
  1. 唯一ID+指纹码机制,利用数据库主键去重
    首先利用Select 语句查询 select count(1) from table where ID = 唯一ID + 指纹码 , 如果查询出来没有结果说明该消息还没有被消费,就可以进行消费。
    注意: 这里的指纹码跟指纹没有什么关系,他指的就是一种自定的规则,可以是时间戳加上一些串码。
    好处: 实现简单
    坏处: 高并发下会有数据库写入的性能瓶颈
    解决方案: 根据ID进行算法路由,分库分表
  2. 利用Redis的原子性
    将消息存储在Redis当中,我们可以利用 Redis的 hasKey() 来判断消息是否已经消费过了。
    使用Redis我们需要考虑两个问题:
    问题一:是否要进行数据库落库,如果落库如何保证数据库和Redis中的数据一致性,比如Redis存储成功,但是写入数据库时失败了。这样就会出现问题,所有要做到同时成功同时失败。
    问题二:如果不实时的进行落库,那么就需要考虑如果设置定时同步策略,毕竟数据存在数据库中还是更稳妥一点。

三、Confirm确认消息

Confirm消息确认机制指的是生产者投递消息后,如果Broker收到消息,则会给生产者一个应答。生产者进行接收应答,用来确定这条消息是否正常的发送到Broker,这种方式也是消息的可靠性投递的核心保障。
在这里插入图片描述
实现流程:
第一步:在channel上开启确认模式:channel.confirmSelect()
第二步:在channel上添加监听:addConfirmListener,监听成功和失败的返回结果,根据具体的结果对消息进行重新发送、或记录日志等后续处理!

四、Return消息机制

Return Listener 用于处理一些不可路由的消息!
一般情况下我们的消息生产者,通过指定一个Exchange和Routingkey,把消息送达到某一个队列中去,然后我们的消费者监听队列,进行消费处理操作!但是在某些情况下,如果我们在发送消息的时候,当前的exchange不存在或者指定的路由key路由不到,这个时候如果我们需要监听这种不可达的消息,就要使用Return Listener。

使用Return消息机制时我们需要注意一个属性的设置:
Mandatory: 如果为true,则监听器会接收到路由不可达的消息,然后进行后续处理,如果为false,那么broker端自动删除该消息,所以如果要使用我们需要设置为true。
在这里插入图片描述

五、消费端的自定义监听

继承DefaultConsumer类,重写里面的handleDelivery即可。不需要再使用循环的方式监听队列。

六、消费端限流

我们假设一个场景,在RabbitMQ服务器有上万条未处理的消息,这时我们随便打开一个消费者客户端,就会出现如下情况:巨量的消息瞬间全部推送过来,但是单个客户端无法同时处理这么多数据,这就可能会导致服务器崩溃出现故障,所以限流就十分重要。
RabbitMQ提供了一种qos(服务质量保证)功能,即在非自动确认消息的前提下,如果一定数目的消息(通过基于consume或者channel设置Qos的值)未被确认前,不进行消费新的消息。(注:要实现限流一定要将自动签收aotoACK设置为false)

七、消费端手动ACK与重回队列

消费端手动ACK与NACK:
当消费端进行消费时,由于一些异常的情况可能导致消费不成功,这时就要发送NACK,让消息重新发送一次重新处理。但是如果达到一定的重试次数还是没有成功那么我就需要手动的发送ACK进行签收,然后可以使用日志将有问题的消息进行记录,后续再人工进行干预处理。
重回队列(requene):
重回队列就是把没有处理成功的消息重新放到队列的尾部。不过在实际使用中,一般都不会使用重回队列。

七、TTL

TTL是Time To Live的缩写,也就是生存时间
RabbitMQ支持消息的过期时间,从消息发出开始计算
RabbitMQ支持队列的过期时间,从消息进入队列开始计算,只要超过了队列的超时时间配置,那么消息会自动的清除

八、死信队列

死信队列:DLX,Dead-Letter-Exchange
当消息在一个队列中变成死信(dead message)之后,它能被重新publish到另一个Exchange,这个Exchange就是死信队列。死信队列也是一个正常的Exchange,和一般的Exchange没有区别,它能在任意的队列上被指定。当这个队列中有死信时,RabbitMQ就会自动的将这个消息重新发布到设置的死信队列上去,进而被路由到另一个队列。(注意:死信队列并不是一个Quene而是一个Exchange)

消息变为死信的情况:

  1. 消息被拒绝(basic.reject/basic.nack),并且requeue=false 也就是重回队列被设置为false
  2. 消息TTL过期
  3. 队列达到最大长度

声明死信队列:

  1. 声明一个Exchange 如 dlx.exchange
  2. 声明一个Quene 如 dlx.quene
  3. 声明RouteKey 为 # 也就是所有的消息都可以被路由到 dlx.quene中
  4. 在声明我们要使用的消费端队列时,添加一个Map参数 arguements
    arguements.put(“x-dead-letter-exchange”,“dlx.exchange”),这样一来该队列就会把队列中的死信发送到 dlx.exchange上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值