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

在系统中当使用消息队列时,无论做哪种技术选型,有很多问题是无论如何也不能忽视的,如:消息必达、消息幂等等。本文以典型的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 {@Autowiredprivate StockService stockService;@Autowiredprivate JedisPool jedisPool;@Autowiredprivate StockFlowService stockFlowService;@RabbitListener(queues = RabbitMQConfig.REDUCE_STOCK_QUEUE)@Transactionalpublic void receiveMessage(Message message){//获取消息idString 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 {//获取消息体中goodsIdgoodsId = 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.rhkb.cn/news/2331.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】线程----同步、互斥、条件变量

目录 3. 同步 3.1 概念 3.2 同步机制 3.3 函数接口 1. 同步 1.1 概念 同步(synchronization)指的是多个任务(线程)按照约定的顺序相互配合完成一件事情 1.2 同步机制 通过信号量实现线程间的同步 信号量:通过信号量实现同步操作;由信号量来决定…

Linux内核的启动

一、需求 Linux系统中内核处于硬件和应用层之间。整个系统启动和初始化的过程,Linux内核是在主处理器启动之后才会执行。不同的处理器启动流程并不相同,这就要求内核能支持各种处理器的初始化操作。Liux内核各个模块,大部分设计时做到了体系…

[手机Linux] ubuntu 错误解决

Ubuntu: 1,ttyname failed: Inappropriate ioctl for device 将 /root/.profile 文件中的 mesg n || true 改为如下内容。 vim /root/.profile tty -s && mesg n || true 2,Errors were encountered while processing: XXX XXXX sudo apt-get --purge remove xxx…

Docker的入门

一、安装Docker 本教程参考官网文档,链接如下: CentOS | Docker Docs 这个教程是基于你的虚拟机已经弄好了(虚拟机用的CentOS),并且有SecureCRT或者MobaXterm等等任意一个工具 1.1 卸载旧版 如果系统中存在旧版本的Docker&a…

Onedrive精神分裂怎么办(有变更却不同步)

Onedrive有时候会分裂,你在本地删除文件,并没有同步到云端,但是本地却显示同步成功。 比如删掉了一个目录,在本地看已经删掉,onedrive显示已同步,但是别的电脑并不会同步到这个删除操作,在网页版…

机器学习06-正则化

机器学习06-正则化 文章目录 机器学习06-正则化0-核心逻辑脉络1-参考网址3-大模型训练中的正则化1.正则化的定义与作用2.常见的正则化方法及其应用场景2.1 L1正则化(Lasso)2.2 L2正则化(Ridge)2.3 弹性网络正则化(Elas…

windows 极速安装 Linux (Ubuntu)-- 无需虚拟机

1. 安装 WSL 和 Ubuntu 打开命令行,执行 WSL --install -d ubuntu若报错,则先执行 WSL --update2. 重启电脑 因安装了子系统,需重启电脑才生效 3. 配置 Ubuntu 的账号密码 打开 Ubuntu 的命令行 按提示,输入账号,密…

微信小程序实现个人中心页面

文章目录 1. 官方文档教程2. 编写静态页面3. 关于作者其它项目视频教程介绍 1. 官方文档教程 https://developers.weixin.qq.com/miniprogram/dev/framework/ 2. 编写静态页面 mine.wxml布局文件 <!--index.wxml--> <navigation-bar title"个人中心" ba…

Qt/C++进程间通信:QSharedMemory 使用详解(附演示Demo)

在开发跨进程应用程序时&#xff0c;进程间通信&#xff08;IPC&#xff09;是一个关键问题。Qt 框架提供了多种 IPC 技术&#xff0c;其中 QSharedMemory 是一种高效的共享内存方式&#xff0c;可以实现多个进程之间快速交换数据。本文将详细讲解 QSharedMemory 的概念、用法及…

[UE4图文系列] 5.字符串转中文乱码问题说明

原文连接&#xff1a;[UE4图文系列] 5.字符串转中文乱码问题说明 - 哔哩哔哩 本例以原生C和UE4 C字符串传输中出现的中文乱码问题进行说明 一.乱码示例: 1.直接用中文字符串初始化FString,在蓝图中进行打印 FString GetStrWithChinese() {FString fstr"这是一句中文"…

人工智能任务19-基于BERT、ELMO模型对诈骗信息文本进行识别与应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能任务19-基于BERT、ELMO模型对诈骗信息文本进行识别与应用。近日&#xff0c;演员王星因接到一份看似来自知名公司的拍戏邀约&#xff0c;被骗至泰国并最终被带到缅甸。这一事件迅速引发了社会的广泛关注。该…

题解 CodeForces 430B Balls Game 栈 C/C++

题目传送门&#xff1a; Problem - B - Codeforceshttps://mirror.codeforces.com/contest/430/problem/B翻译&#xff1a; Iahub正在为国际信息学奥林匹克竞赛&#xff08;IOI&#xff09;做准备。有什么比玩一个类似祖玛的游戏更好的训练方法呢&#xff1f; 一排中有n个球…

通过proto文件构建 完整的 gRPC 服务端和客户端案例

基础教程-简单案例&#xff08;快入入门java-grpc框架&#xff09; 参考官方入门案例教程&#xff1a;里面我看proto编译&#xff0c;其实直接用maven就能直接将.proto文件编译成java代码。快速入门 | Java | gRPC 框架https://grpc.org.cn/docs/languages/java/quickstart/ …

Mysql--运维篇--备份和恢复(逻辑备份,mysqldump,物理备份,热备份,温备份,冷备份,二进制文件备份和恢复等)

MySQL 提供了多种备份方式&#xff0c;每种方式适用于不同的场景和需求。根据备份的粒度、速度、恢复时间和对数据库的影响&#xff0c;可以选择合适的备份策略。主要备份方式有三大类&#xff1a;逻辑备份&#xff08;mysqldump&#xff09;&#xff0c;物理备份和二进制文件备…

如何修复Android上未安装的应用程序

在Android设备上安装应用程序通常是一个简单的过程。然而&#xff0c;“ Android上未安装应用程序”是一种常见的智能手机错误消息&#xff0c;由于一个或多个原因而经常遇到。发现由于即将出现故障而无法充分利用手机&#xff0c;这当然会非常令人沮丧&#xff0c;但幸运的是&…

干净卸载Windows的Node.js环境的方法

本文介绍在Windows电脑中&#xff0c;彻底删除Node.js环境的方法。 在之前的文章Windows系统下载、部署Node.js与npm环境的方法&#xff08;https://blog.csdn.net/zhebushibiaoshifu/article/details/144810076&#xff09;中&#xff0c;我们介绍过在Windows电脑中&#xff0…

初始Java4

目录 一.继承 1.定义&#xff1a; 2.继承的语法&#xff1a; 3.子类访问父类 4.子类构造方法 5.super与this 6.继承方法 7.final关键字 &#xff08;1&#xff09;.变量不变 &#xff08;2&#xff09;.方法不变 &#xff08;3&#xff09;.类不可继承 8.继承与组合…

算法竞赛(蓝桥杯)贪心算法1——数塔问题

题目描述 有如下所示的数塔&#xff0c;要求从底层走到顶层&#xff0c;若每一步只能走到相邻的结点&#xff0c;则经过的结点的数字之和最大是多少&#xff1f; 输入 输入数据首先包括一个整数整数 N (1≤N≤100)&#xff0c;表示数塔的高度&#xff0c;接下来用 N 行数字表示…

MATLAB学习笔记-table

1.在table中叠加table table 的每一列具有固定的数据类型。如果要让表的所有单元格都可以任意填充&#xff0c;就得让每一列都是 cell 类型&#xff0c;这样表中每个单元格都是“一个元胞”。创建时可以先构造一个 空 cell 数组&#xff08;大小为行数列数&#xff09;&#x…

RabbitMQ(三)

RabbitMQ中的各模式及其用法 工作队列模式一、生产者代码1、封装工具类2、编写代码3、发送消息效果 二、消费者代码1、编写代码2、运行效果 发布订阅模式一、生产者代码二、消费者代码1、消费者1号2、消费者2号 三、运行效果四、小结 路由模式一、生产者代码二、消费者代码1、消…