RabbitMQ如何保证消息的可靠性?

        在了解RabbitMQ如何保证消息的可靠性之前,我们可以先看一下RabbitMQ的执行的过程。

         在一次消息的传递之间,要经历上面的几个步骤,如果我们要保证消息的可靠性,那么必须在这些过程中入手,分为三个部分:(1)生产者 (2)MQ本身 (3)消费者

(1) 生产者

        生产者将我们的数据发送到RabbitMQ的时候,在传输数据的过程中,可能会导致数据的丢失,那么我们怎么样才能保证传输的时候数据不丢失呢?RabbitMQ提供了以下两种处理方式。

  • 事务功能

     我们可以使用RabbitMQ提供的事务功能,在我们发送数据之前,通过语句channel.txSelect开启事务功能,然后就可以发送消息了。

  • 如果消息成功投递到RabbitMQ,那么事务提交成功,可通过语句channel.txCommit进行提交。
  • 如果消息没有成功被RabbitMQ接收到,生产者就会收到对应的异常报错,那么就可以回滚我们的事务,可通过语句channel.txRollback进行回滚。

        使用这种方式有个缺点就是:我们的吞吐量降低,因为开启这种方式十分地消耗性能,因此是不推荐的。因此可以使用其他的方式解决上面提到的问题。

  • confirm模式

        使用这种方法的时候,我们通过在生产者这边开启confirm模式,在我们每次发送消息的时候,就会对应地分配一个唯一的id

  • 如果我们的消息成功地写入到了RabbitMQ中,那么RabbitMQ就会对应地给我们回传一个ack消息,告诉我们这个消息成功地投递过去了。
  • 如果RabbitMQ并没有处理这个消息的话,那么就会回调一个nack接口,告诉我们这个消息接收失败了,我们可以试着重发。

我们可以通过上面的这个机制,在我们的内存里维护每个消息id的状态,如果说,超过一定的时间了,我们还没有接收到消息的回调,不清楚这条信息是否能够成功投递到我们的RabbitMQ中,那么我们可以自己进行重发。

  • 区别

        通过上面的分析,其实我们可以看出,事务机制与confirm机制最大的不同在于:事务机制是同步的,而confirm机制是异步的

        当我们使用事务机制的时候,我们提交了一个事务,此时就会堵塞在那边了,等待事务执行的结果,确认它是成功投递,还是发生异常没有投递到RabbitMQ中。

        而使用confirm机制的时候,由于实现的机制是异步的,我们在发送了一条消息了以后,就可以发送下一条信息了,投递过去的消息会在RabbitMQ接收到,并且通过异步回调我们一个接口通知我们这条消息接收到了,如果返回的时ack,那么就是成功投递,反之为nack就是没有成功,我们可以进行消息的重发。

总结:一般在生产者这边,为了避免数据的丢失,我们可以使用confirm机制进行消息的投送。

(2) MQ

        RabbitMQ会不会丢失我们的数据呢?显然是会的,假设RabbitMQ将消息发送给消费者的时候,刚好RabbitMQ挂掉了,这就很尴尬了,消息还没投递到消费者那边过去,这就导致了这个数据的丢失,所以RabbitMQ提供了持久化的机制,用于处理上面说到的问题。

        在开启了RabbitMQ的持久化机制以后,消息写入之后就会被持久化到磁盘当中,此时哪怕RabbitMQ自己挂掉了,我们在重启RabbitMQ的时候,就会进行恢复,自动读取之前存储的数据,所以说一般数据是不会丢的,设置持久化有以下两个步骤:

  • 第一,我们在创建queue的时候,需要将queue设置为持久化,这样子就可以保证RabbitMQ能持久化queue的元数据(exchange、queue、binding、user、policy等数据),但是不会持久化queue里面的数据。
  • 第二,发送消息的时候将消息的deliveryMode模式(交付模式)设置为2,此时就会将消息设置为持久化,RabbitMQ就会将消息持久到磁盘上去。

        这里必须注意的点就是,我们需要同时设置这两个持久化才行。此时哪怕RabbitMQ挂掉了,再次重启,也能从我们的磁盘中恢复queue,恢复queue中的数据。

        这里的持久化机制可以同上面讲到的confirm机制结合起来,只有当消息被持久化到磁盘了之后才能通知生产者ack了。所以说,哪怕是在持久化数据到磁盘之前,我们的RabbitMQ挂了,数据丢失了,生产者收不到ack,那么我们自己就可以进行重发了。

        当然,这里说的持久化机制其实还是有一点缺陷的。即使我们给RabbitMQ开启了持久化机制,也有一种可能,就是消息写到了RabbitMQ的时候,还没来得及持久化到磁盘的时候,很不巧,RabbitMQ就刚好挂掉了,那么就会导致数据丢失的问题。不过只是丢失的只是这一点点的数据,问题不大,毕竟出现这种事情的概率也比较低。

总结:我们可以开启RabbitMQ提供的持久化机制保证MQ这边不会丢失消息。

(3) 消费端

        在消费端,也就是consumer这边,当我们在消费这条消息的时候,才刚开始消费,结果此时的进程挂掉了,比如说刚好就重启了,就挺突然的,尴尬的是RabbitMQ都认为我们消费完了,这个时候数据就丢失了。当然我们也不用怕,RabbitMQ给我们提供了ack机制,用于处理这些情况。

        简单来说,我们可以关闭RabbitMQ的自动ack机制,采用手动ack机制来进行代替。在我们的代理里面,确保每次处理完一条消息了以后,自己在程序里面进行ack。这样子的话,如果我们还没有处理完一条消息,那么就不会返回ack,那么RabbitMQ就不会认为我们已经处理完消息了,这个时候RabbitMQ是会将这个消费分配给别的consumer区处理的,这样子就能保证我们的消息是不会丢失的。

总结:在消费者这端,我们可以用手动ack机制代替自动ack机制。

(4) 总结

        下面以一张图作为总结,对应给出了RabbitMQ如何保证消息可靠性的全部方案,如下:

RabbitMQ 作为一款开源的消息队列系统,为了保证消息的可靠传输和处理,采用了以下几个关键机制: 1. **确认机制(Acknowledgements)**:当消费者成功接收到消息后,会向 RabbitMQ 中心节点发送一个确认,如果中心节点没有收到确认,会重新将消息放入队列等待消费者的再次处理,直到超时或达到重试次数。 2. **持久化(Persistence)**:RabbitMQ 可以将消息写入磁盘,即使服务器宕机也能保证数据不丢失,恢复后可以从上次的位置继续处理。 3. **事务(Transactions)**:对于需要原子性的操作,RabbitMQ 支持 AMQP 协议中的事务模式,确保一系列消息要么全部发送成功,要么全部失败并回滚。 4. **死信队列(Dead Letter Exchange)**:如果消息在长时间内无人消费或者多次重试失败,会被路由到死信队列,这样可以避免无限循环的情况,并提供一种人工干预处理异常的方式。 5. **镜像(Clustering and Mirroring)**:RabbitMQ 集群部署可提供高可用性和故障转移功能,即使某个节点失效,消息也可以被其他节点接管,保证服务不间断。 6. **幂等性(Idempotency)**:RabbitMQ 提供了消息路由和路由键的概念,同一个消息多次投递会产生相同的效果,避免了重复处理。 相关问题-- 1. RabbitMQ如何处理消息丢失的情况? 2. 什么情况下会触发死信队列? 3. 在RabbitMQ集群中,如何实现负载均衡和故障切换?
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值