MQ 架构设计原理与消息中间件详解(三)

news2024/10/7 2:54:02

RabbitMQ实战解决方案

RabbitMQ死信队列

死信队列产生的背景

RabbitMQ死信队列俗称,备胎队列;消息中间件因为某种原因拒收该消息后,可以转移到死信队列中存放,死信队列也可以有交换机和路由key等。

产生死信队列的原因
  1. 消息投递到MQ中存放 消息已经过期  消费者没有及时的获取到我们消息,消息如果存放到mq服务器中过期之后,会转移到备胎死信队列存放。
  2. 队列达到最大的长度 (队列容器已经满了)
  3. 消费者消费多次消息失败,就会转移存放到死信队列中

 

代码整合 参考 Boyatop-springboot-rabbitmq|#中order-dead-letter-queue项目

死信队列的架构原理

死信队列和普通队列区别不是很大

普通与死信队列都有自己独立的交换机和路由key、队列和消费者。

区别:

1.生产者投递消息先投递到我们普通交换机中,普通交换机在将该消息投到

普通队列中缓存起来,普通队列对应有自己独立普通消费者。

2.如果生产者投递消息到普通队列中,普通队列发现该消息一直没有被消费者消费

的情况下,在这时候会将该消息转移到死信(备胎)交换机中,死信(备胎)交换机

对应有自己独立的 死信(备胎)队列 对应独立死信(备胎)消费者。

死信队列应用场景

1.30分钟订单超时设计

  1. Redis过期key :
  2. 死信延迟队列实现:

采用死信队列,创建一个普通队列没有对应的消费者消费消息,在30分钟过后

就会将该消息转移到死信备胎消费者实现消费。

备胎死信消费者会根据该订单号码查询是否已经支付过,如果没有支付的情况下

则会开始回滚库存操作。

RabbitMQ消息幂等问题

RabbitMQ消息自动重试机制
  1. 当我们消费者处理执行我们业务代码的时候,如果抛出异常的情况下

在这时候mq会自动触发重试机制,默认的情况下rabbitmq是无限次数的重试。

需要人为指定重试次数限制问题

  1. 在什么情况下消费者需要实现重试策略?

A.消费者获取消息后,调用第三方接口,但是调用第三方接口失败呢?是否需要重试?

该情况下需要实现重试策略,网络延迟只是暂时调用不通,重试多次有可能会调用通。

B.消费者获取消息后,因为代码问题抛出数据异常,是否需要重试?

该情况下是不需要实现重试策略,就算重试多次,最终还是失败的。
可以将日志存放起来,后期通过定时任务或者人工补偿形式。

如果是重试多次还是失败消息,需要重新发布消费者版本实现消费

可以使用死信队列

Mq在重试的过程中,有可能会引发消费者重复消费的问题。

Mq消费者需要解决 幂等性问题

幂等性 保证数据唯一

方式1:

生产者在投递消息的时候,生成一个全局唯一id,放在我们消息中。

Msg id=123456

Msg id=123456

Msg id=123456

消费者获取到我们该消息,可以根据该全局唯一id实现去重复。

全局唯一id 根据业务来定的  订单号码作为全局的id

实际上还是需要再db层面解决数据防重复。

业务逻辑是在做insert操作 使用唯一主键约束

业务逻辑是在做update操作 使用乐观锁

  1. 当消费者业务逻辑代码中,抛出异常自动实现重试 (默认是无数次重试)
  2. 应该对RabbitMQ重试次数实现限制,比如最多重试5次,每次间隔3s;重试多次还是失败的情况下,存放到死信队列或者存放到数据库表中记录后期人工补偿
如何合理选择消息重试
  1. 消费者获取消息后,调用第三方接口,但是调用第三方接口失败呢?是否需要重试 ?
  2. 消费者获取消息后,应该代码问题抛出数据异常,是否需要重试?

总结:如果消费者处理消息时,因为代码原因抛出异常是需要从新发布版本才能解决的,那么就不需要重试,重试也解决不了该问题的。存放到死信队列或者是数据库表记录、后期人工实现补偿。

Rabbitmq如何开启重试策略

spring:
 
rabbitmq:
   
####连接地址
   
host: 127.0.0.1
   
####端口号
   
port: 5672
   
####账号
   
username: guest
   
####密码
   
password: guest
   
### 地址
   
virtual-host: /booya_rabbitmq
   
listener:
     
simple:
       
retry:
         
####开启消费者(程序出现异常的情况下会)进行重试
         
enabled: true
         
####最大重试次数
         
max-attempts: 5
         
####重试间隔次数
         
initial-interval: 3000

消费者重试过程中,如何避免幂等性问题

重试的过程中,为了避免业务逻辑重复执行,建议提前全局id提前查询,如果存在

的情况下,就无需再继续做该流程。

重试的次数最好有一定间隔次数,在数据库底层层面保证数据唯一性,比如加上唯一id

SpringBoot开启消息确认机制
配置文件新增
spring:

  rabbitmq:

    ####连接地址

    host: 127.0.0.1

    ####端口号

    port: 5672

    ####账号

    username: guest

    ####密码

    password: guest

    ### 地址

    virtual-host: /booyaVirtualHosts

    listener:

      simple:

        retry:

          ####开启消费者(程序出现异常的情况下会)进行重试

          enabled: true

          ####最大重试次数

          max-attempts: 5

          ####重试间隔次数

          initial-interval: 3000

        acknowledge-mode: manual

  datasource:

    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8

    username: root

    password: root

    driver-class-name: com.mysql.jdbc.Driver
消费者ack代码
@Slf4j

@Component

@RabbitListener(queues = "fanout_order_queue")

  public class FanoutOrderConsumer {

  

    @Autowired

    private OrderManager orderManager;

    @Autowired

    private OrderMapper orderMapper;

  

    @RabbitHandler

    public void process(OrderEntity orderEntity, Message message, Channel channel) throws IOException {

  //        try {

        log.info(">>orderEntity:{}<<", orderEntity.toString());

        String orderId = orderEntity.getOrderId();

        if (StringUtils.isEmpty(orderId)) {

            log.error(">>orderId is null<<");

            return;

        }

        OrderEntity dbOrderEntity = orderMapper.getOrder(orderId);

        if (dbOrderEntity != null) {

            log.info(">>该订单已经被消费过,无需重复消费!<<");

            // 无需继续重试

            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

            return;

        }

        int result = orderManager.addOrder(orderEntity);

  

        log.info(">>插入数据库中数据成功<<");

        if (result >= 0) {

            // 开启消息确认机制      channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

        }

  //        int i = 1 / 0;

//        } catch (Exception e) {

//            // 将失败的消息记录下来,后期采用人工补偿的形式

  //        }

    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2193434.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何只修改obsidian图片链接为markdown

如何只修改obsidian图片链接为markdown 前言插件配置 使用注意 前言 适合有一定了解obsidian用法和插件市场&#xff0c;还有相对路径的人 插件 在obsidian插件市场搜索—开梯子 配置 首先使用ctrlp打开命令面板&#xff0c;也可以在左侧通过图标打开命令面板&#xff0c…

VTC视频时序控制器,TPG图像测试数据发生器,LCD驱动——FPGA学习笔记19

详情可以见LCD篇 LCD彩条显示——FPGA学习笔记10_依次显示红绿蓝三个通道-CSDN博客 一、VTC简介 Video Timing Controller 缩写 VTC 是我们在所有涉及 FPGA 图像、 FPGA 视频类方案中经常用到的一种用于产生视频时序的控制器。 本课以 VGA 为切入点&#xff0c; 学习视频传输…

【颜色平衡树 / E】

题目 思路 DFS暴力 60分 代码 #include <bits/stdc.h> using namespace std; const int N 5010; const int M 5010; int h[N], e[M], ne[M], idx; int c[N], f; int ans; void add(int a, int b) // 添加一条边a->b {e[idx] b, ne[idx] h[a], h[a] idx ; } …

C++ 观察者模式

观察者模式&#xff08;Observer Pattern&#xff09;是一种行为设计模式&#xff0c;用于在对象之间建立一对多的依赖关系&#xff0c;当一个对象的状态发生变化时&#xff0c;它的所有依赖对象都会得到通知并自动更新。 在观察者模式中&#xff0c;主题和观察者之间是松耦合…

Vue - 路由用法

前端路由就是URL中的hash与组件之间的对应关系。Vue Router是Vue的官方路由。 组成&#xff1a; VueRouter&#xff1a;路由器类&#xff0c;根据路由请求在路由视图中动态渲染选中的组件。<router-link>&#xff1a;请求链接组件&#xff0c;浏览器会解析成<a>。…

S7-200 SMART Modbus RTU常见问题

1.S7-200 SMART 是否支持 Modbus ASCII 通信模式&#xff1f; STEP 7-Micro/WIN SMART 软件未提供Modbus ASCII 通信模式指令库。S7-200 SMART CPU若用于Modbus ASCII 通信时&#xff0c;则需要用户使用自由口通信模式进行编程。 2.S7-200 SMART CPU 集成的RS485 端口&#xf…

毕设 基于大数据情感分析的网络舆情分析系统(源码+论文)

简介 今天学长向大家介绍一个大数据毕设项目 毕设分享 基于大数据情感分析的网络舆情分析系统(源码论文) &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;4分创新点&#xff1a;4分 &#x1f9ff; 项目分享:见文末! 实…

Linux下网络转发功能

1、背景介绍 项目中使用上位机电脑&#xff0c;需要通过网络访问一个Linux主机&#xff0c;但是该Linux主机没有网络直接与上位机相连&#xff0c;只能通过插箱内另外一个Linux主机转发才能访问&#xff0c;示意图如下&#xff1a; 2、网络转发配置 Linux网络中转主机需要进行…

Java体系中的异常

1. 异常 1.1 异常的概念 在Java中&#xff0c;我们将程序执行过程中发生的不正常行为称为异常。异常是在程序运行过程中发生的错误或意外情况&#xff0c;它打破了程序的正常执行流程。在Java中通过面向对象的编程思想&#xff0c;我们也将这些扰乱程序正常执行的行为用类组织…

三菱FX3UPLC定位模式介绍

运行模式的比较 *1用相对定位指令代替。 *2使用相对/绝对定位指令。 *3使用直线插补指令的连续路径功能。 *4使用直线插补指令的连续路径功能。 可单轴运行。 *5.使用表格运行(连续运行功能)。 *6.使用中断定位指令。 *7只支持FX3UFX3UC可编程控制器&#xff0c;使用可变速脉…

设计模式之装饰器模式(Decorator)

一、装饰器模式介绍 装饰模式(decorator pattern) 的原始定义是&#xff1a;动态的给一个对象添加一些额外的职责。 就扩展功能而言&#xff0c;装饰器模式提供了一种比使用子类更加灵活的替代方案。 在软件设计中&#xff0c;装饰器模式是一种用于替代继承的技术&#xff0c;它…

Java语法之异常

1.异常的概念以及体系结构 1.1 异常的概念 在生活中人会生病,比如咳嗽流鼻涕,头晕等,程序也一样,比如:数据格式不匹配,网络不通畅,内存报警等.在Java中,我们把程序执行的不正常行为称为异常. 比如: 1. 算数异常 System.out.println(10 / 0); // 执行结果 Exception in thread &…

python导出requirements.txt的几种方法

整理了python导出requirements.txt的几种方法和流程 Condapippipreqs 最近又碰到整理requirements.txt的问题&#xff0c;有好几种命令可以做到这一点&#xff0c;但是之前整理的时候会输出一堆乱七八糟的包&#xff0c;这次挨个试了所有方法&#xff0c;特此记录。我的平台是a…

【本地缓存】Java 中的 4 种本地缓存

目录 1、手写一个简单的本地缓存1.1、封装缓存实体类1.2、创建缓存工具类1.3、测试 2、Guava Cache2.1、Guava Cache 简介2.2、入门案例2.2.1、引入 POM 依赖2.2.2、创建 LoadingCache 缓存 2.3、Guava Cache 的优劣势和适用场景 3、Caffeine3.1、Caffeine 简介3.2、对比 Guava…

elasticsearch ES DBA常用语句

一、 查看集群状态 curl -uelastic 连接串:端口/_cluster/health?pretty 集群健康有三种状态&#xff1a;green,yellow,red green&#xff1a;所有主要分片、复制分片都可用yellow&#xff1a;所有主要分片可用&#xff0c;但不是所有复制分片都可用red&#xff1a;不是所有…

基于SSM的学生信息管理系统【附源码】

​基于SSM的学生信息管理系统&#xff08;源码L文说明文档&#xff09; 目录 4 系统设计 4.1界面设计原则 4.2功能结构设计 4.3数据库设计 4.3.1数据库概念设计 4.3.2 数据库物理设计 第5章 系统实现 5.1管理员功能实现 5.1.1班级和课程关…

基于企业现状定制化的数字化转型路径和战略性架构规划

如何从企业现状出发规划数字化转型 随着技术的迅猛发展&#xff0c;全球企业都在加速推进数字化转型&#xff0c;以增强市场竞争力并提升运营效率。数字化转型并不是一个统一的模板&#xff0c;它要求企业结合自身的业务现状、行业环境和技术基础&#xff0c;制定个性化的转型…

通信工程学习:什么是B/S浏览器服务器模式

B/S&#xff1a;浏览器服务器模式 B/S&#xff08;Browser/Server&#xff0c;浏览器/服务器&#xff09;模式&#xff0c;又称B/S结构&#xff0c;是Web兴起后的一种网络结构模式。在这种模式中&#xff0c;Web浏览器是客户端最主要的应用软件&#xff0c;系统功能实现的核心部…

分享一个基于.net的学生信息管理系统 C#高校教务管理系统(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

计算机毕业设计 智慧物业服务系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…