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分钟后接收消息,检查支付状态:

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

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

相关推荐
云泽8083 小时前
从ENIAC到Linux:计算机技术与商业模式的协同演进
linux·运维·服务器
沈艺强3 小时前
l2tp over ipsec lac 和lns 永久连接
网络
ZeroNews内网穿透3 小时前
企业远程访问方案选择:何时选内网穿透,何时需要反向代理?
运维·服务器·网络·python·安全
勤奋的小王同学~4 小时前
(网络编程)网络编程套接字 UDP的socket API 代码解析
网络
paopaokaka_luck4 小时前
绿色环保活动平台(AI问答、WebSocket即时通讯、协同过滤算法、Echarts图形化分析)
java·网络·vue.js·spring boot·websocket·网络协议·架构
wow_DG4 小时前
【WebSocket✨】入门之旅(三):WebSocket 的实战应用
网络·websocket·网络协议
NiKo_W4 小时前
Linux 深入理解权限
linux·运维·服务器
江流月照4 小时前
PCIE地址空间介绍
java·服务器·网络
代码炼金术士4 小时前
服务器更换jar包,重启后端服务
服务器·jar
郝学胜-神的一滴4 小时前
深入探索 Python 元组:从基础到高级应用
运维·服务器·开发语言·python·程序人生