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

RabbitMQ---应用问题

(一)幂等性介绍

幂等性是本身是数学中的运算性质,他们可以被多次应用,但是不会改变初始应用的结果

1.应用程序的幂等性介绍

包括很多,有数据库幂等性,接口幂等性以及网络通信幂等性等

  就比如数据库的select操作,这个操作就是符合幂等性的,虽然不同时间查询的结果会不同,但是幂等性指的是对资源的影响,而不是返回结果,查询数据本质上是不会对资源产生影响的,所以即使两次查询结果不同,那也是因为查询间有一些其他的操作对资源进行了修改

 我们再来看接口的幂等性,就是说同一个接口多次调用,对系统的影响是相同的,就比如多次调用支付接口(同一个订单),对系统的影响也是一样的(也就是只生效一次)

2.MQ的幂等性

 对于MQ而言,幂等性是指,同一条消息,被多次消费,对系统的影响也是相同的

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

1)At most once:最多⼀次. 消息可能会丢失,但绝不会重复传输

2)At least once:最少⼀次. 消息绝不会丢失,但可能会重复传输.

 3. Exactly once:恰好⼀次. 每条消息肯定会被传输⼀次且仅传输⼀次.

RabbitMQ只支持最多一次和最少一次,对于恰好一次,我们目前还做不到这么精准

在业务使用中,对于一些可靠性高的场景,建议使用最少一次,以防止我们消息的丢失,在一些不需要高可靠性的场景,我们可以使用最多一次,就比如我们日志的记录

那我们就来看一下什么情况下会导致同一条消息被多次消费

首先就是发送时消息重复:

  当一条消息已经成功发送到交换机并成功到达队列完成持久化,此时出现了网络问题导致MQ没有给生产者发送ack,这样就会导致生产者重新发送一条消息到交换机,此时就会导致发送时消息重复(这两条内容是一样的)

还有消费时消息重复:

  当消息已经从队列给消费者并且完成业务处理应该返回ack的时候,网络出现问题,导致ack丢失了,这样MQ就会认为消息没有被成功消费,此时就会触发重试机制,MQ重新给消费者传递消息

  最少一次会有一个问题,消费端会手动重复的消息,就会对同一条消息进行多次处理,就有可能出现一些问题,如果此时我们消息不是幂等性的,比如扣款业务,就会出现多次扣款的情况

3.解决方案

MQ消费者幂等性的解决方案一般有以下几种:

1)全局唯一id

1.为每一条消息都分配一个标识符,可以是UUID也可以是自增ID但是一定要保证唯一性

2.消费者收到消息后,先去判断该id是否消费过如果消费过就放弃处理,如果没消费,消费者就开始消费消息,并且把ID保存到数据库中

这里我们可以使用redis原子性操作setnx来保证幂等性,把唯一ID作为key放到redis中,返回1就说明之前没有消费过,返回0就说明之前存在,就放弃处理

 2)业务逻辑判断

  在业务逻辑层面实现消息处理的幂等性,就比如我们先判断数据库中是否有相关数据记录,或者使用乐观锁机制避免已被其他事务更改的数据,或者检查相关业务的状态,如果是未处理,我们再进行处理

(二)顺序性保证

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

在很多业务场景下,消息的消费是不用保证顺序的,只需要执行就可以了,就比如我们订单的处理,先处理哪一个都可以,但是还有一些就不可以,比如对用户信息的修改,一个用户在很短时间内对同一个资料进行修改,就需要我们保证消息的顺序

   我们RabbitMQ本质上是不能够保障顺序性的,在不考虑消息丢失,网络问题,并且只有一个消费者和一个生产者,点对点的情况下,是可以保障消息的顺序性,如果有多个生产者同时发送消息,我们就无法确定到达队列的顺序,就更无法确定到达消费者的顺序,也就无法保证顺序性

那除了这种还有什么情况会打破顺序性?

1)有多个消费者:当队列有多个消费者的时候,消息会被不同消费者处理,有的消费者处理的快有的处理的慢,所以我们消息处理的顺序性是无法保证的

2)网络波动或异常:在消息传递时如果ack丢失,就会使得消息重新入队,重新消费,造成顺序性问题

3)消息重试:这个在多个消费者会出问题。如果消费者处理消息未完全确认,那么就会触发重试机制,会影响消息处理的顺序性问题

4)消息路由问题:消息会根据routingkey被映射到不同的队列,从而无法保证全局的顺序性

5)死信队列:如果消息被拒绝放到死信队列,那么就会导致消息被消费的顺序打乱

顺序性保障方案

那如何来保障我们消息的顺序性?

我们分为局部顺序性保证和全局顺序性保证

局部顺序性通常指在一个队列内保证消息顺序,全局顺序性是指在全部队列内保证消息顺序

在实际应用中,全局顺序很难实现,相对来说局部顺序更加常见和容易实现

接下来说一下

消息的顺序保障的常见方法

1.单队列单消费者

最简单方法就是使用单个队列,队列由一个消费者进行处理

2.分区消费

单个消费者吞吐量太低,我们需要多个消费者并且还要保障顺序的时候,就可以使用分区消费,把一个队列分成多个队列,每个队列分配一个消费者,我们可以根据id进行哈希然后分成多个队列,这样我们只需要保障每个队列的顺序性即可

但是RabbitMQ本身不支持分区消费,所以需要业务逻辑实现,我们可以使用Spring-cloud-stream来实现

Partitioning with the RabbitMQ Binder :: Spring Cloud Stream

3.消息确认机制

消息确认就是消费者在处理完一条消息后,显示发送确认,这样RabbitMQ才会继续发送其他消息

4.业务逻辑控制

在一些情况下,即使消息的顺序不对,也可以通过我们设置序列号,然后在消费信息时进行判断来处理,保证顺序性

注:我们保证顺序性不是说上面一个就可以,要把上面的方法进行结合

RabbitMQ本⾝并不保证全局的严格顺序性,特别是在分布式系统中.在实际应⽤开发中根据具体的业 务需求,可能需要结合多种策略来实现所需要的顺序保证

(三)消息积压问题

消息积压是指在消息队列中,待处理的消息超过了消费者的处理能力,导致消息在队列中不断积压

产生消息积压有以下原因:

1.消息生产过快:在高流量情况下,生产者用高速率发送消息,超过了消费者的处理能力

2.消费者处理能力慢:消费者消费消息的速度低于生产者生产的速度,导致队列积压

这里可能有以下原因:

消费者的业务逻辑复杂,消费端代码性能低,系统资源限制,异常处理不当

3.网络问题:网络延迟或者不稳定,消费者无法立刻接收或者确认消息,导致消息积压

4.RabbitMQ服务配置低,消息积压会导致系统性能下降,影响用户体验,导致系统崩溃

解决方案:

1.提高消费者效率

增加消费者实例数量,比如新增机器

提高业务逻辑,使用多线程进行处理

设置消息分发,当一个消费者阻塞,把消息分发给其他消费者

消息发生异常,设置重试策略,或者转入死信队列

2.限制生产者速度

流量控制:在消息生产者设置流量控制逻辑

限流:使用限流工具,给消息发送速率设置上限

设置过期时间:消息到过期时间后,可以配置死信队列,等消费者空闲后,再进行消费

3.资源和配置优化:

升级RabbitMQ服务器的硬件,调整MQ参数


http://www.kler.cn/a/511852.html

相关文章:

  • LeetCode:2266. 统计打字方案数(DP Java)
  • vue+高德API搭建前端3D交通页面
  • 【2024年华为OD机试】(C卷,100分)- 悄悄话 (Java JS PythonC/C++)
  • 第5章:Python TDD定义Dollar对象相等性
  • 如何在不暴露MinIO地址的情况下,用Spring Boot与KKFileView实现文件预览
  • MQ消息队列
  • 回顾2024年度 - 挑战之旅:学习、生活与成长的华丽蜕变
  • 【无标题】微调是迁移学习吗?
  • Django简介与虚拟环境安装Django
  • leetcode763.划分字母区间
  • Android 存储进化:分区存储
  • 【博客之星2024年度总评选】年度回望:我的博客之路与星光熠熠
  • Android 极光推送快速开发集成指南(1)
  • Grafana系列之Dashboard:新增仪表板、新增变量、过滤变量、变量查询、导入仪表板、变量联动、Grafana Alert
  • 第9章:Python TDD解决货币对象相等性比较难题
  • python爬虫报错日记
  • 初始JavaEE篇 —— 快速上手 SpringBoot
  • 【Redis】Redis 集群中节点之间如何通信?
  • [cg] glProgramBinary
  • JavaScript系列(35)-- WebSocket应用详解
  • Redis系列之底层数据结构字典Dict
  • 图像处理|顶帽操作
  • Kivy App开发之UX控件Bubble气泡
  • 使用redis-cli命令实现redis crud操作
  • Meta标签教程:提升网站SEO与用户体验的利器
  • 人工智能之数学基础:线性代数中的线性相关和线性无关