RabbitMQ高级

目录

发送者的可靠性

发送者重连

发送者确认

MQ的可靠性

数据持久化

[Lazy Queue](#Lazy Queue)

消费者的可靠性

消费者确认机制

失败重试策略

业务幂等性

唯一消息id

业务判断

延迟消息

死信交换机

延迟消息插件

取消超时订单


消息可靠性问题

消息转发给交换机可能面临断网,交换机发送给队列可能队列也会无法

发送者的可靠性

发送者重连

有的时候由于网络波动,可能会出现发送者连接MQ失败的情况。通过配置我们可以开启连接失败后的重连机制:

注意

当网络不稳定的时候,利用重试机制可以有效提高消息发送的成功率。不过 SpringAMQP 提供的重试机制是阻塞式的重试,也就是说多次重试等待的过程中,当前线程是被阻塞的,会影响业务性能。

如果对于业务性能有要求,建议禁用重试机制。如果一定要使用,请合理配置等待时长和重试次数,当然也可以考虑使用异步线程来执行发送消息的代码。

发送者确认

SpringAMQP提供了Publisher Confirm和Publisher Return两种确认机制。开启确认机制后,当发送者发消息给MQ后,MQ会返回确认结果给发送者。返回的结果有以下几种情况:

  • 消息投递到了 MQ,但是路由失败。此时会通过 PublisherReturn 返回路由异常原因,然后返回 ACK,告知投递成功
  • 临时消息投递到了 MQ,并且入队成功,返回 ACK,告知投递成功
  • 持久消息投递到了 MQ,并且入队完成持久化,返回 ACK,告知投递成功
  • 其它情况都会返回 NACK,告知投递失败

1.在publisher这个微服务的application.yml中添加配置:

配置说明:

这里的publisher-confirm-type有三种模式可选:

none:关闭confirm机制

simple:同步阻塞等待MQ的回执消息

correlated:MQ异步回调方式返回回执消息

  1. 每个RabbitTemplate只能配置一个ReturnCallback,因此需要在项目启动过程中配置:

3.发送消息,指定消息ID、消息ConfirmCalback(每个消息都需要配置)

MQ的可靠性

在默认情况下,RabbitMQ 会将接收到的信息保存在内存中以降低消息收发的延迟。这样会导致两个问题:

  • 一旦 MQ 宕机,内存中的消息会丢失
  • 内存空间有限,当消费者故障或处理过慢时,会导致消息积压,引发 MQ 阻塞

数据持久化

RabbitMQ实现数据持久化包括3个方面:

交换机持久化

队列持久化

交换机和队列不管是用代码创建还是手动创建都是持久化的

消息持久化(需要手动指定,但是代码发送的消息默认都是持久化的)

Lazy Queue

从 RabbitMQ 的 3.6.0 版本开始,就增加了 Lazy Queue 的概念,也就是惰性队列。

惰性队列的特征如下:

  • 接收到消息后直接存入磁盘,不再存储到内存
  • 消费者要消费消息时才会从磁盘中读取并加载到内存(可以提前缓存部分消息到内存,最多 2048 条)
    在 3.12 版本后,所有队列都是 Lazy Queue 模式,无法更改。

要设置一个队列为懒惰队列,只需要在声明队列时,指定x-queue-mode属性为lazy即可:

消费者的可靠性

消费者确认机制

消费者确认机制是为了确认消费者是否成功处理消息。当消费者处理消息结束后,应该向RabbitMQ发送一个回执,告知RabbitMQ自己消息处理状态:

  • ack:成功处理消息,RabbitMQ 从队列中删除该消息
  • nack:消息处理失败,RabbitMQ 需要再次投递消息
  • reject:消息处理失败并拒绝该消息,RabbitMQ 从队列中删除该消息

SpringAMQP 已经实现了消息确认功能。并允许我们通过配置文件选择 ACK 处理方式,有三种方式:

  • none:不处理。即消息投递给消费者后立刻 ack,消息会立刻从 MQ 删除。非常不安全,不建议使用
  • manual:手动模式。需要自己在业务代码中调用 api,发送 ack 或 reject,存在业务入侵,但更灵活
  • auto:自动模式。SpringAMQP 利用 AOP 对我们的消息处理逻辑做了环绕增强,当业务正常执行时则自动返回 ack。当业务出现异常时,根据异常判断返回不同结果:
    • 如果是业务异常,会自动返回 nack
    • 如果是消息处理或校验异常,自动返回 reject

失败重试策略

SpringAMQP提供了消费者失败重试机制,在消费者出现异常时利用本地重试,而不是无限的requeue到mq。我们可以通过在application.yaml文件中添加配置来开启重试机制:

在开启重试模式后,重试次数耗尽,如果消息依然失败,则需要有 MessageRecoverer 接口来处理,它包含三种不同的实现:

  • RejectAndDontRequeueRecoverer:重试耗尽后,直接 reject,丢弃消息。默认就是这种方式
  • ImmediateRequeueMessageRecoverer:重试耗尽后,返回 nack,消息重新入队
  • RepublishMessageRecoverer:重试耗尽后,将失败消息投递到指定的交换机

将失败处理策略改为RepublishMessageRecoverer:

1.首先,定义接收失败消息的交换机、队列及其绑定关系

2.然后,定义RepublishMessageRecoverer

业务幂等性

幂等在程序开发的概念是指同一个业务,执行一次或多次对业务状态的影响是一致的。

唯一消息id

方案一,是给每个消息都设置一个唯一 id,利用 id 区分是否是重复消息:

① 每一条消息都生成一个唯一的 id,与消息一起投递给消费者。

② 消费者接收到消息后处理自己的业务,业务处理成功后将消息 ID 保存到数据库

③ 如果下次又收到相同消息,去数据库查询判断是否存在,存在则为重复消息放弃处理。

业务判断

方案二,是结合业务逻辑,基于业务本身做判断。以我们的余额支付业务为例:

延迟消息

延迟消息:发送者发送消息时指定一个时间,消费者不会立刻收到消息,而是在指定时间之后才能收到消息。

延迟任务:设置在一定时间之后才执行的任务

死信交换机

当一个队列中的消息满足下列情况之一时,就会成为死信(dead letter):

  • 消费者使用 basic.reject 或 basic.nack 声明消费失败,并且消息的 requeue 参数设置为 false
  • 消息是一个过期消息(达到了队列或消息本身设置的过期时间),超时无人消费
  • 要投递的队列消息堆积满了,最早的消息可能成为死信

如果队列通过dead-letter-exchange属性指定了一个交换机,那么该队列中的死信就会投递到这个交换机中。这个交换机被称为死信交换机

延迟消息插件

这个插件可以将普通交换机改造为支持延迟消息功能的交换机,当消息投递到交换机后可以暂存一段时间,到期后再投递到队列

安装:RabbitMQ入门指南(十一):延迟消息-延迟消息插件_rabbitmq 延时插件-CSDN博客

取消超时订单

用户下单完成后,发送15分钟延迟消息,在15分钟后接收消息,检查支付状态:

已支付:更新订单状态为已支付

未支付:更新订单状态未关闭订单,恢复商品库存

相关推荐
IDIOT___IDIOT3 小时前
Linux mount 命令
linux·运维·服务器
暗流者3 小时前
AAA 服务器与 RADIUS 协议笔记
运维·服务器·笔记
青草地溪水旁6 小时前
服务发现实例和服务实例是不同的
服务器·服务发现·服务实例
算力魔方AIPC8 小时前
如何用算力魔方4060安装PaddleOCR MCP 服务器
运维·服务器
tan77º8 小时前
【Linux网络编程】分布式Json-RPC框架 - 项目设计
linux·服务器·网络·分布式·网络协议·rpc·json
Ray Song8 小时前
【Linux】 wget、curl 用法区别
linux·运维·服务器·curl·wget
.Shu.9 小时前
计算机网络 各版本TLS握手的详细过程
网络·计算机网络
半路_出家ren9 小时前
路由综合实验RIP,OSPF,BGP
网络·网络协议·rip·ospf·ebgp·ibgp
小妖6669 小时前
本地文件夹即时变身 Web 服务器(文件服务器)
运维·服务器