RabbitMQ如何保证消息的可靠性

RabbitMQ如何保证消息的可靠性

1、保证消息不丢失(三步)

  • 开启事务(不推荐)
  • 开启confirm(推荐)
  • 开启RabbitMQ持久化(交换机、队列、消息)
  • 关闭RabbitMQ自动ack(改成手动)

2、保证消息不重复消费

幂等性 ( 每个消息用一个唯一标识来区分,消费前先判断标识有没有被消费过,若已消费过,则直接 ACK)

3RabbitMQ如何保证消息的顺序性

将消息放入同一个交换机,交给同一个队列,这个队列只有一个消费者,消费者只允许同时开启一个线程

4RabbitMQ消息重试机制

消费者在消费消息的时候,如果消费者业务逻辑出现程序异常,这时候应该如何处理?

使用消息重试机制 (SpringBoot 默认 3 次消息重试机制 )

如何合适选择重试机制?

消费者取到消息后,调用第三方接口,接口无法访问,需要使用重试机制
消费者取到消息后,抛出数据转换异常,不需要重试机制,需要发布者进行解决。

5SpringBoot消息重试机制

@EnableRetry 注解:表示启用重试机制(value 表示哪些异常需要触发重试, maxAttempts 设置最大重试次数,delay 表示重试的延迟时间, multiplier 表示上一次延时时间是这一次的倍数 )
eg @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000,
multiplier = 1.5))
@Recover 注解:当重试次数达到设置的最大次数的时候,程序还是执行异常,调用的回调函数。

6RabbitMQ死信队列

死信队列是当消息在一个队列因为下列原因 :
a 、消息被拒绝 (basic.reject basic.nack) 并且 requeue=false.
b 、消息 TTL 过期
c 、队列达到最大长度 ( 队列满了,数据无法添加到 mq )
变成了 死信队列 后被重新投递 (publish) 到另一个 Exchange ,然后重新消费。说白了就是没有被消费 的消息换个地方重新被消费

7RabbitMQ解决分布式事务

经典案例,以目前流行的外卖为例,用户下单后,调用订单服务,订单服务调用派单系统通知送外卖人 员送单,这时候订单系统与派单系统采用MQ 异步通讯。
RabbitMQ 解决分布式事务原理
答案:采用最终一致性原理 需要保证以下三要素 :
a 、确保生产者一定要将数据投递到 MQ 服务器中 ( 采用 MQ 消息确认机制 )
b 、确保消费者能够正确消费消息,采用手动 ACK 模式 ( 注意重试、幂等性问题 )
c 、如何保证第一个事务先执行,采用补偿机制,在创建一个补单消费者进行监听,如果订单没有创建成 功,进行补单。( 如果第一个事务中出错,补单消费者会在重新执行一次第一个事务,例如第一个事务是 添加订单表,如果失败在补单的时候重新生成订单记录,由于订单号唯一,所以不会重复)

8RabbitMQ保证消息不丢失的具体方案

前提
  • (1)开启confirm
  • (2)开启RabbitMQ的持久化(交换机、队列、消息)
  • (3)关闭RabbitMQ的自动ack(改成手动)
  • (4)配置消费重试次数,消费重试间隔时间等
涉及到的技术点:
  • MQRedis、定时任务

8.1、保证投放消息不丢失

(1)先将消息放入生产者Redis(此时消息的状态为未投放),再放入队列

(2)根据confirm(ReturnCallbackConfirmCallback)的结果来确定消息是否投递成功,

投递成功的,修改生产者redis中消息的投递状态为已投递

投递失败的消息将会放入失败的Redis,并从生产者Redis中删除,由定时任务定期扫描并重新投递

(3)生产者Redis定时任务

生产者Redis定时任务专门扫描生产者Redis中存放了一定时间,但是状态还是未投放的消息

此消息会被认为已经投递,但是没有任何反馈结果(由于不可知因素,导致没有ReturnCallback,也没有 ConfirmCallback),

此类消息被扫描到后,会放入失败的Redis,并从生产者Redis中删除,由定时任务定期扫描并重新投递

(4)还需要一个专门的定时任务扫描生产者Redis中存放了很久,仍然未消费的数据(状态为已投递),此类 消息被扫描到后,会放入失败的Redis,并从生产者Redis中删除,由定时任务定期扫描并重新投递

(5)扫描失败的Redis的定时任务都遵循一条原则,一条消息最多被重新投递三次,若投递了三次仍然失 败,则记录日志,记录到数据库,不会再投递,需要人工干预处理

8.2、保证消费消息不丢失

(1)消费者取到消息后,从消息中取出唯一标识,先判断此消息有没有被消费过,若已消费过,则直接 ACK(避免重复消费)

(2)正常处理成功后,将生产者Redis中的此消息删除,并ACK(告诉server端此消息已成功消费)

(3)遇到异常时,捕获异常,验证自己在消息中设定的重试次数是否超过阀值,若超过,则放入死信队 列,若未超过,则向将消息中的重试次数加1,抛出自定义异常,进入重试机制

(4)有专门的消费者用于处理死信队列中消费多次仍未消费成功的数据,可以记录日志,入库,人工干预 处理

 

每天努力一点,每天都在进步

  • 10
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
RabbitMQ 通过持久化和确认机制来保证消息可靠性。 在发送消息时,可以设置消息的 delivery mode 为 2,表示消息需要被持久化。持久化的消息会被写入磁盘,即使 RabbitMQ 服务器宕机或重启,消息也不会丢失。 在接收消息时,可以使用确认机制。当消费者成功处理了一条消息后,会向 RabbitMQ 发送确认消息。如果 RabbitMQ 收到确认消息,就会将该消息从队列中删除,否则该消息会被重新发送。通过确认机制,可以保证消息不会被重复消费。 以下是一个简单的 RabbitMQ 发送和接收消息的示例代码: ``` import pika connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) channel = connection.channel() # 声明队列 channel.queue_declare(queue='hello', durable=True) # 发送消息 channel.basic_publish(exchange='', routing_key='hello', body='Hello World!', properties=pika.BasicProperties(delivery_mode=2)) print(" [x] Sent 'Hello World!'") # 接收消息 def callback(ch, method, properties, body): print(" [x] Received %r" % body) ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_qos(prefetch_count=1) channel.basic_consume(queue='hello', on_message_callback=callback) print(' [*] Waiting for messages. To exit press CTRL+C') channel.start_consuming() ``` 在这个示例中,我们设置了队列的 durable 属为 True,表示队列需要被持久化。在发送消息时,我们设置了消息的 delivery mode 为 2,表示消息需要被持久化。在接收消息时,我们使用了确认机制,通过调用 ch.basic_ack() 方法确认消息已经被消费。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

powerfuler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值