当前位置: 首页 > news >正文

RabbitMQ ⑤-顺序性保障 || 消息积压 || 幂等性

在这里插入图片描述

幂等性保障

幂等性(Idempotency) 是计算机科学和网络通信中的一个重要概念,指的是某个操作无论被执行多少次,所产生的效果与执行一次的效果相同。

应用程序的幂等性:
在应用程序中,幂等性就是指对一个系统进行重复调用(相同的参数),不论请求多少次,这些请求对系统的影响都是相同的结果。

比如数据库的 select 操作,不同时间两次查询的结果可能不同,但是这个操作是符合幂等性的,幂等性指的是对资源的影响,而不是返回结果。

查询操作对数据资源本身不会产生影响,之所以结果不同,可能是因为两次查询之间有其他操作对资源进行了修改。

比如 i++ 操作,就是非幂等性的,如果调用方法没有控制好逻辑,一次流程重复调用好几次,结果就会不同。

MQ 幂等性
对于 MQ 而言,幂等性就是指同一条消息,无论被消费者消费多少次,对系统的影响都是一样的。

一般消息中间件的消息传输保障分为三个层级:

  • 最多一次(At most once):消息可能会丢失,但绝不会重发。
  • 至少一次(At least once):消息绝不会丢失,但有可能会重复消费。
  • 恰好一次(Exactly once):消息绝对不会丢失,也不会重复消费。

RabbitMQ 提供了 At most onceAt least once 两种消息传输保障,但并不提供 Exactly once 保障,这是因为主流的消息队列中间件都没有提供这种保障。

在实际业务中,建议使用 最少一次最多一次 可能会导致因为网络问题、消费出现异常等等问题,导致消息丢失。

但是 最少一次 就会导致消息重发导致消息重复消费:

  • 服务器发送给生产者的确认报文可能会因为网络等问题而丢失,导致生产者认为消息发送失败,然后重新发送消息给服务器。
  • 消费者发送给服务器的确认报文也可能会因为网络等问题而丢失,导致服务器认为消息消费失败,然后发送给消息到消费者。

解决方案

全局唯一ID

  1. 为每条消息都分配一个标识符,比如 UUID 或者消息的唯一ID,总之保证其唯一性即可。
  2. 消费者收到该消息后,先判断该消息是否已经被消费过,如果消费过,则忽略该消息。
  3. 如果未消费过,则消费该消息,并将该消息的唯一 ID 记录到数据库或者缓存中,以便下次判断。(可以使用 Redissetnx 命令实现)

业务逻辑判断

在业务逻辑层面实现消息的幂等性。

顺序性保障

消息的顺序性是指消费者消费消息的顺序和生产者发送消息的顺序一致

如果有多个生产者同时发送消息,是无法确定消息到达 RabbitMQ Broker 的前后顺序,也就无法保证消息的顺序性。

有以下几种情况可能会打破消息的顺序性:

  • 多个消费者:但队列配置多个消费者时,消息可能会被不同的消费者并行处理,从而导致消息处理的顺序性无法保证。
  • 网络波动或异常:由于网络等异常,导致消息被重发,从而导致消息的顺序性被打乱。
  • 消息重试:如果消费者处理消息失败,则会将该消息重新放入队列,也就是消息重试,导致消息的顺序性被打乱。
  • 消息路由问题:在复杂的路由场景中,消息可能会根据不同的路由键被分发到不同的队列,从而导致消息的顺序性被打乱。
  • 死信队列:如果消费者处理消息失败,则会将该消息放入死信队列,导致消息的顺序性被打乱。

保障方案

顺序性保障分为两种:全局性顺序保障局部性顺序保障

全局性顺序保障是指在多个队列或多个消费者之间保证消息的顺序。

局部性顺序保障通常指的是在单个队列内部保证消息的顺序。

在实际开放中,全局性保障的实现较为复杂,RabbitMQ 作为一个分布式消息队列,保障的是高吞吐量和高可用性,而不是严格的顺序性保障,如果业务场景确实需要严格的顺序性保障,建议在应用层代码逻辑里作额外的处理。

常见的顺序性保障方案

  • 单队列单消费者: 最简单的方法是使用单个队列,并由单个消费者进行处理。同一个队列中的消息是先进先出的,这是 RabbitMQ 来帮助我们保证的。
  • 分区消费:单个消费者的吞吐太低了,当需要多个消费者以提高处理速度时,可以使用分区消费。把一个队列分割成多个分区,每个分区由一个消费者进行处理,以此来保持每个分区内消息的顺序性。
    • RabbitMQ 本身并不支持分区消费,需要业务逻辑去实现,或者借助Spring Cloud Stream 来实现。
    • 详细参考:Spring Cloud Stream RabbitMQ 分区消费

消息积压问题

消息积压是指在消息队列中,待处理的消息数量超过了消费者的处理能力,导致消费者处理不过来,消息堆积在队列中,积压的消息越来越多,最终导致消息队列的阻塞。

  • 生产者的维度看:消息生产过快,在流量高峰期,生产者以极高的速率发送消息,导致消息积压。
  • 消费者的维度看:消费者处理能力不足,消费者处理不过来,消息积压。
    • 消费端业务逻辑复杂,耗时长。
    • 消费端代码性能低下。
    • 系统资源限制,如 CPU、内存、磁盘IO 等限制消费者处理消息的效率。
    • 异常处理不当,消费者在处理消息时出现异常,导致消息无法被正确处理和确认。
  • 网络问题
  • RabbitMQ 服务器配置低下

解决方案

  • 提高消费者的效率
    • 增加消费者实例数量,比如新增机器。
    • 优化业务逻辑和性能
    • 设置 prefetchCount 参数,限制每个消费者所能接收的消息数量,从而提高消费者的处理能力。
    • 消息发生异常时,设置合理的重试策略,或者转入死信队列。
  • 限制生产者的发送速度
    • 流量控制
    • 限流
    • 设置过期时间
  • 资源与配置优化
    • 升级服务器硬件配置,提高 CPU、内存、磁盘IO 等资源的利用率。
    • 优化 RabbitMQ 服务器配置,设置合理的配置。

相关文章:

  • PyCharm2025的字体的设置
  • 【常用算法:进阶篇】13.位运算全解析:从底层原理到高效算法
  • 易路 AI 招聘:RPA+AI 颠覆传统插件模式,全流程自动化实现效率跃迁
  • 音视频之H.265/HEVC速率控制
  • 图的几种存储方法比较:二维矩阵、邻接表与链式前向星
  • 利用Spring Boot和Redis构建高性能缓存系统
  • 使用MybatisPlus实现sql日志打印优化
  • 洛谷P1093 [NOIP 2007 普及组] 奖学金
  • 丝杆升降机在锂电行业的自动化应用有什么?
  • MySQL 存储过程优化实践:项目合同阶段数据自动化处理
  • 基于 ABP vNext + CQRS + MediatR 构建高可用与高性能微服务系统:从架构设计到落地实战
  • 源码分析之Leaflet中TileLayer
  • Linux Bash 中 $? 的详细用法
  • 每日算法 -【Swift 算法】寻找两个有序数组的中位数(O(log(m+n)))详细讲解版
  • 深挖navigator.webdriver浏览器自动化检测的底层分析
  • k8s1.27版本集群部署minio分布式
  • jQuery Ajax中dataType 和 content-type 参数的作用详解
  • MySQL 8.0 OCP 英文题库解析(六)
  • Java中字符串(String类)的常用方法
  • 海康威视摄像头C#开发指南:从SDK对接到安全增强与高并发优化
  • 花290多万维修保质期仅一年多?媒体四问凤阳鼓楼“瓦片脱落”
  • 国家发改委谈稳定外资:将研究制定鼓励外资企业境内再投资政策措施
  • 牛市早报|年内首次存款利率下调启动,5月LPR今公布
  • 零跑汽车一季度营收破百亿元:净亏收窄至1.3亿元,毛利率14.9%创新高
  • 半年不到再换岗:伊春市委常委、政法委书记方春彪任伊春森工集团党委书记
  • 男子服用头孢后饮酒应酬致昏迷在家,救援人员破门施救后脱险