业务幂等性技术架构体系之消息幂等深入剖析

news2025/1/16 9:00:39

在系统中当使用消息队列时,无论做哪种技术选型,有很多问题是无论如何也不能忽视的,如:消息必达、消息幂等等。本文以典型的RabbitMQ为例,讲解如何保证消息幂等的可实施解决方案,其他MQ选型均可参考。

一、消息重试机制

消息队列的消息幂等性,主要是由MQ重试机制引起的。因为消息生产者将消息发送到MQ-Server后,MQ-Server 会将消息推送到具体的消息消费者。假设由于网络抖动或出现异常时,MQ-Server根据重试机制就会将消息重新向 消息消费者推送,造成消息消费者多次收到相同消息,造成数据不一致。

在RabbitMQ中,消息重试机制是默认开启的,但只会在consumer出现异常时,才会重复推送。在使用中,异常 的出现有可能是由于消费方又去调用第三方接口,由于网络抖动而造成异常,但是这个异常有可能是暂时的。所以 当消费者出现异常,可以让其重试几次,如果重试几次后,仍然有异常,则需要进行数据补偿。

消费重试配置

# 消费者监听相关配置 
    listener: 
        simple: 
            retry: 
            # 开启消费者(程序出现异常)重试机制,默认开启并一直重试 
            enabled: true 
            # 最大重试次数 
            max‐attempts: 5 
            # 重试间隔时间(毫秒) 
            initial‐interval: 3000

当consumer消息监听类中添加异常,最终接受消息时,可以发现,消息在接收五次后,最终出现异常。

二、消息幂等解决

以上就是我们的消息幂等解决的架构图

下面看代码实现

修改OrderController
/**
     * 此处为了方便演示,不做基础添加数据库操作
     * @return
     */
@PostMapping("/addOrder")
public String addOrder(){

    String uniqueKey = String.valueOf(idWorker.nextId());

    MessageProperties messageProperties = new MessageProperties();
    messageProperties.setMessageId(uniqueKey);
    messageProperties.setContentType("text/plain");
    messageProperties.setContentEncoding("utf-8");
    Message message = new Message("1271700536000909313".getBytes(),messageProperties);
    rabbitTemplate.convertAndSend(RabbitMQConfig.REDUCE_STOCK_QUEUE,message);

    return "success";
}
新增消息监听类
@Component
public class ReduceStockListener {

    @Autowired
    private StockService stockService;

    @Autowired
    private JedisPool jedisPool;

    @Autowired
    private StockFlowService stockFlowService;

    @RabbitListener(queues = RabbitMQConfig.REDUCE_STOCK_QUEUE)
    @Transactional
    public void receiveMessage(Message message){

        //获取消息id
        String messageId = message.getMessageProperties().getMessageId();

        Jedis jedis = jedisPool.getResource();

        System.out.println(messageId);
        try {

            //redis锁去重校验
            if (!"OK".equals(jedis.set(messageId, messageId, "NX", "PX", 300000))){
                System.out.println("重复请求");
                return;
            }

            //mysql状态校验
            if (!(stockFlowService.findByFlag(messageId).size() == 0)){
                System.out.println("数据已处理");
                return;
            }

            String goodsId = null;
            try {
                //获取消息体中goodsId
                goodsId = new String(message.getBody(),"utf-8");
                stockService.reduceStock(goodsId,messageId);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            int nextInt = new Random().nextInt(100);
            System.out.println("随机数:"+nextInt);
            if (nextInt%2 ==0){
                int i= 1/0;
            }


        } catch (RuntimeException e) {
            //解锁
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            jedis.eval(script, Collections.singletonList(messageId), Collections.singletonList(messageId));
            System.out.println("出现异常了");
            System.out.println(messageId+":释放锁");
            throw e;
        }
    }
}

生产者的死信队列投递自行完成

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

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

相关文章

【2024年华为OD机试】 (B卷,100分)- 跳房子I(Java JS PythonC/C++)

一、问题描述 题目描述 跳房子,也叫跳飞机,是一种世界性的儿童游戏。 游戏参与者需要分多个回合按顺序跳到第1格直到房子的最后一格。 跳房子的过程中,可以向前跳,也可以向后跳。 假设房子的总格数是count,小红每…

鸿蒙打包发布

HarmonyOS应用/元服务发布(打包发布) https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/ide-publish-app-V13?catalogVersionV13 密钥:包含非对称加密中使用的公钥和私钥,存储在密钥库文件中,格式…

JAVA:在IDEA引入本地jar包的方法(不读取maven目录jar包)

问题: 有时maven使用的jar包版本是最新版,但项目需要的是旧版本,每次重新install会自动将mavan的jar包覆盖到项目的lib目录中,导致项目报错。 解决: 在IDEA中手动配置该jar包对应的目录。 点击菜单File->Projec…

Mac上安装Label Studio

在Mac上安装Anaconda并随后安装Label Studio,可以按照以下步骤进行: 1. 在Mac上安装Anaconda 首先,你需要从Anaconda的官方网站下载适用于Mac的安装程序。访问Anaconda官网,点击“Download Anaconda”按钮,选择适合M…

docker-compose和docker仓库

一、docker-compose 1.概述 docker-compose是一个自动编排工具,可以根据dockerfile自动化部署docker容器。 主要功能 配置定义 使用YAML文件(通常命名为docker - compose.yml)来描述应用程序的服务、网络和卷等配置。 容器编排 可以同时…

了解linux中的“of_property_read_u32()”

of_property_read_u32(node, "post-pwm-on-delay-ms",&data->post_pwm_on_delay); /*根据"post-pwm-on-delay-ms",从属性中查找并读取一个32位整数*/ /*读到一个32位整数,保存到data->post_pwm_on_delay中*/ of_property_read_u32…

nodejs 037: 前端新手教程使用引导库 Intro.js

Intro.js简介 Intro.js 是一个流行的引导库,用于提供步进式的新手教程。它可以帮助你创建用户引导,展示一些步骤和提示,逐步引导用户了解应用程序的功能。 安装方法: npm install intro.js使用方法: import introJ…

Vue篇-07

Vue UI组件库 一、移动端常用的UI组件库 1.1、Vant 1.2、Cube UI 1.3、Mint UI 二、PC端常用的UI组件库 2.1、Element UI Element - The worlds most popular Vue UI framework 安装: 按需引入: 135_尚硅谷Vue技术_element-ui按需引入_哔哩哔哩_b…

适配器模式案例

如果在这样的结构中 我们在Controller中注入,但我们后续需要修改Oss时,比如从minioService改成AliyunService时,需要改动的代码很多。于是我们抽象出一个FileService,让controller只跟fileservice耦合,这样我没只需要在…

鸿蒙UI开发——键盘弹出避让模式设置

1、概 述 我们在鸿蒙开发时,不免会遇到用户输入场景,当用户准备输入时,会涉及到输入法的弹出,我们的界面针对输入法的弹出有两种避让模式:上抬模式、压缩模式。 下面针对输入法的两种避让模式的设置做简单介绍。 2、…

Vue2+OpenLayers实现折线绘制功能(提供Gitee源码)

目录 一、案例截图 二、安装OpenLayers库 三、代码实现 3.1、初始变量 3.2、画一条折线 3.3、完整代码 四、Gitee源码 一、案例截图 二、安装OpenLayers库 npm install ol 三、代码实现 3.1、初始变量 关键代码: data() {return {map:null,// 定义路径坐…

栈算法篇——LIFO后进先出,数据与思想的层叠乐章(上)

文章目录 前言第一章:栈的基础知识回顾1.1 栈的结构与实现1.2 栈的应用第二章:删除字符串中的所有相邻重复项2.1 题目链接:https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/description/2.2 题目分析:2.3…

计算机的错误计算(二百一十二)

摘要 利用两个大模型计算 实验表明,两个大模型均进行了中肯的分析。另外,其中一个大模型给出了 Python代码,运行后,结果中有7位错误数字;而一个大模型进行加减运算时出错。 例1. 计算 下面是与一个大模型的对话…

VMware虚拟机安装Home Assistant智能家居平台并实现远程访问保姆级教程

目录 前言 1. 安装Home Assistant 前言 本文主要介绍如何在windows 10 上用VMware Workstation 17 Pro搭建 Home Assistant OS Host os version:Windows 10 Pro, 64-bit (Build 19045.5247) 10.0.19045 VMware version:VMware Workstation 17 Pro 1. 安装Home …

HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载,Scroll滚动到顶部

HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载 效果展示 使用方法 import LoadingText from "../components/LoadingText" import PageToRefresh from "../components/PageToRefresh" import FooterBar from "../components/…

【开源免费】基于Vue和SpringBoot的欢迪迈手机商城(附论文)

本文项目编号 T 141 ,文末自助获取源码 \color{red}{T141,文末自助获取源码} T141,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

Cyber Security 101-Offensive Security-SQLMap: The Basics(sqlmap基础)

了解 SQL 注入并通过 SQLMap 工具利用此漏洞。 任务1:介绍 SQL 注入是一个普遍存在的漏洞,长期以来一直是热门 网络安全主题。要了解这个漏洞,我们必须首先 了解什么是数据库以及网站如何与数据库交互。 数据库是可以存储、修改和 检索。它…

【数据结构-堆】力扣1792. 最大平均通过率

一所学校里有一些班级,每个班级里有一些学生,现在每个班都会进行一场期末考试。给你一个二维数组 classes ,其中 classes[i] [passi, totali] ,表示你提前知道了第 i 个班级总共有 totali 个学生,其中只有 passi 个学…

USRP,FM解调程序

USRP,FM解调程序

洛谷 P1101 单词方阵刷题笔记

题目 https://www.luogu.com.cn/problem/P1101 题目要求输出包含 yizhong 所有方向排列的矩阵图 观察答案除了yizhong 均为星号 因此我们可以用bool数组来标记每个位置的状态 定义星号为无效状态 false 我们对原矩阵图 进行遍历 每当找到一个y就试一下它各个方向是否满…