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

使用 RabbitMQ 实现秒杀订单系统的异步消息处理

使用 RabbitMQ 实现秒杀订单系统的异步消息处理

在秒杀系统中,如何确保高并发环境下的订单处理稳定高效是个很大的挑战。为了解决这个问题,我们通常会引入消息队列,通过异步处理来削峰填谷。这篇文章将详细讲解如何使用 RabbitMQ 来设计一个秒杀订单系统的异步消息处理流程,重点是如何使用交换机(Exchange)、队列(Queue)、路由键(Routing Key)以及死信队列(Dead Letter Queue)来管理订单的状态。

1. 为什么需要使用消息队列?

在秒杀系统中,用户的请求量在极短时间内会成倍增加。如果每个请求都直接访问数据库,极有可能导致数据库崩溃甚至出现库存超卖的情况。为了避免这种情况,通常会通过引入 RabbitMQ 来将订单处理变为异步,先把订单请求写入队列,然后由消费者从队列中逐个取出进行处理。这样一来,前端响应速度会加快,同时也减轻了数据库的压力。

2. 系统设计概述

在这套秒杀系统中,我们设计了以下几个关键组件:

  • 秒杀订单的主交换机和队列:用于处理异步下单请求。
  • 成功和失败的订单队列:分别处理订单处理成功和失败的消息。
  • 死信队列(Dead Letter Queue):处理超时或者其他异常导致的消息失败。

我们使用了 TopicExchange 来根据路由键将消息发送到不同的队列。每个订单请求在被处理时,首先会进入秒杀队列,然后根据处理结果被转发到成功或失败的队列。处理成功的订单如果超时未支付,会被转发到死信队列,进行进一步处理(例如取消订单、回滚库存等)。

3. 配置 RabbitMQ

下面我们通过配置类 RabbitMQConfig 来详细展示如何定义和绑定 RabbitMQ 的交换机、队列、路由键,以及死信队列。

3.1 定义交换机

在 RabbitMQ 中,交换机是负责将消息路由到相应队列的组件。我们定义了三个交换机:

  • SECKILL_EXCHANGE:用于秒杀队列的交换机,负责接收用户的下单请求。
  • SECKILL_EXCHANGE_ORDER:用于订单处理的交换机,将订单路由到成功或失败的队列。
  • DEAD_LETTER_EXCHANGE_SECKILL_ORDER:死信交换机,处理那些订单失败或者超时的情况。
@Bean
public TopicExchange seckillExchange() {return new TopicExchange(SECKILL_EXCHANGE);
}@Bean
public TopicExchange seckillExchangeOrder() {return new TopicExchange(SECKILL_EXCHANGE_ORDER);
}@Bean
public TopicExchange deadLetterExchangeOrder(){return new TopicExchange(DEAD_LETTER_EXCHANGE_SECKILL_ORDER);
}

通过以上代码,我们分别为秒杀订单、成功/失败处理、以及死信处理定义了各自的交换机。

3.2 定义队列

队列是存放消息的地方。我们定义了以下几个队列:

  • SECKILL_QUEUE:秒杀队列,用户下单请求会被异步地写入这个队列。
  • SECKILL_QUEUE_ORDER_SUCCESS:处理成功订单的队列,订单处理完成后消息会进入这里。
  • SECKILL_QUEUE_ORDER_FAIL:处理失败订单的队列。
  • DEAD_LETTER_QUEUE_SECKILL_ORDER:死信队列,用于处理超时或者异常未完成的订单。
@Bean
public Queue seckillQueue() {return new Queue(SECKILL_QUEUE, true);
}@Bean
public Queue seckillQueueOrderSuccess() {return QueueBuilder.durable(SECKILL_QUEUE_ORDER_SUCCESS).withArgument("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE_SECKILL_ORDER).withArgument("x-dead-letter-routing-key", DEAD_LETTER_ROUTINGKEY_SECKILL_ORDER).withArgument("x-message-ttl", 300000)  // 消息5分钟过期.build();
}@Bean
public Queue seckillQueueOrderFail() {return new Queue(SECKILL_QUEUE_ORDER_FAIL, true);
}@Bean
public Queue deadLetterQueueSeckillOrder() {return new Queue(DEAD_LETTER_QUEUE_SECKILL_ORDER, true);
}

其中,seckillQueueOrderSuccess 队列设置了一个 5 分钟的 TTL(消息过期时间)。如果订单在 5 分钟内未支付,消息将被发送到死信队列,以便进行进一步处理。

3.3 绑定队列和交换机

RabbitMQ 的消息流转需要通过绑定(Binding)来实现。绑定将队列和交换机通过路由键连接在一起。我们为每个队列和交换机进行了相应的绑定:

// 秒杀队列与秒杀交换机绑定
@Bean
public Binding seckillBinding(Queue seckillQueue, TopicExchange seckillExchange) {return BindingBuilder.bind(seckillQueue).to(seckillExchange).with(SECKILL_ROUTINGKEY);
}// 秒杀成功订单队列和秒杀订单交换机绑定
@Bean
public Binding seckillOrderSuccessBinding(Queue seckillQueueOrderSuccess, TopicExchange seckillExchangeOrder){return BindingBuilder.bind(seckillQueueOrderSuccess).to(seckillExchangeOrder).with(SECKILL_ROUTINGKEY_ORDER_SUCCESS);
}// 秒杀失败订单队列和秒杀订单交换机绑定
@Bean
public Binding seckillOrderFailBinding(Queue seckillQueueOrderFail, TopicExchange seckillExchangeOrder){return BindingBuilder.bind(seckillQueueOrderFail).to(seckillExchangeOrder).with(SECKILL_ROUTINGKEY_ORDER_FAIL);
}// 绑定死信队列到死信交换机
@Bean
public Binding bindingDeadLetterQueue(Queue deadLetterQueueSeckillOrder, TopicExchange deadLetterExchangeOrder) {return BindingBuilder.bind(deadLetterQueueSeckillOrder).to(deadLetterExchangeOrder).with(DEAD_LETTER_ROUTINGKEY_SECKILL_ORDER);
}

通过这些绑定,消息会根据路由键从交换机流向相应的队列。比如用户的订单消息会先进入 SECKILL_QUEUE,然后根据订单的处理结果转发到 SECKILL_QUEUE_ORDER_SUCCESSSECKILL_QUEUE_ORDER_FAIL

4. 死信队列的作用

在这套设计中,死信队列的作用至关重要。死信队列用于接收那些无法正常处理的消息,比如订单支付超时或者系统异常。死信队列绑定了一个死信交换机,当消息过期(如上文的 5 分钟 TTL)或者被拒绝时,会自动进入死信队列。这样我们就能针对这些问题订单进行统一处理,比如取消订单、回滚库存等操作。

相关文章:

使用 RabbitMQ 实现秒杀订单系统的异步消息处理

使用 RabbitMQ 实现秒杀订单系统的异步消息处理 在秒杀系统中,如何确保高并发环境下的订单处理稳定高效是个很大的挑战。为了解决这个问题,我们通常会引入消息队列,通过异步处理来削峰填谷。这篇文章将详细讲解如何使用 RabbitMQ 来设计一个…...

oracle19.3单机升级到Oracle19.22

1.补丁包、opatch准备 -rw-r--r-- 1 oracle oinstall 1817908992 9月 10 14:25 p35943157_190000_Linux-x86-64.zip -rw-r--r-- 1 oracle oinstall 133535622 9月 10 14:22 p6880880_190000_Linux-x86-64.zip2.解压补丁包和opatch包 先将原有opatch备份 [oraclecyptdg ~]$…...

半导体的发展--创世新产品介绍

文章目录 半导体的发展 半导体的发展 现代社会对于芯片的需求是越来越多了,90 年代我们能在收音机,电视机,DVD,上面看到芯片的身影,进入 2000 年,电脑,手机逐渐进入中国家庭,中国高…...

Ubuntu WSL使用技巧

0 Preface/Foreword 1 默认为root用户 当下载完成Ubuntu之后,首次登录,当完成初始化后,提示输入新的用户名时候,直接点击右上角的X按钮,再重新登陆,系统会默认使用root权限登录。...

4 个步骤带你快速上手 Einstein Copilot for Tableau

如果你的企业仍未部署或希望迁移至 Tableau Cloud,可考虑订阅 Tableau 高级套件。 自 Einstein Copilot for Tableau 发布以来,相信部分用户已经尝试过在 Tableau Cloud 中借助 AI 对话助理,快速解决数据分析中的问题,获得更准确的…...

C++ | Leetcode C++题解之第386题字典序排数

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> lexicalOrder(int n) {vector<int> ret(n);int number 1;for (int i 0; i < n; i) {ret[i] number;if (number * 10 < n) {number * 10;} else {while (number % 10 9 || numbe…...

vsftpd配置用户和密码让其他客户端连接

一、第一个主机:vsftpd下载及配置 前置准备: #卸载防火墙 yum -y remove firewalld #为了不让防火墙有影响&#xff0c;iptables配置也清空 iptables -F vim /etc/selinux/conf SELINUXdisabled #主要是把它改为disabled或者permissive SELINUXTYPEtargeted #重启linux让seli…...

Oracle使用序列后提示违反唯一约束---解决办法

1、问题原因分析 出现这个问题的原因是插入数据的时候&#xff0c;由于之前没有使用序列插入&#xff0c;而是直接插入了一个比当前序列nextval还大的值&#xff0c;即直接将id写死了。后面再使用序列插入的时候&#xff0c;如果序列小于该值的话&#xff0c;是可以正常插入的…...

乐观锁悲观锁

乐观锁 乐观锁的核心思想是“尽量不去锁定资源&#xff0c;而是尽量让线程并发地工作”&#xff0c;并在最后阶段检查冲突&#xff0c;只有在检测到冲突时才会采取纠正措施。乐观锁通常通过以下方式实现&#xff1a; 版本号控制&#xff1a;每次对共享资源进行修改时&#xf…...

Unity面试:什么是UnityEvent?

UnityEvent是Unity引擎中一种特殊的事件系统&#xff0c;属于Unity的事件和委托机制。它允许开发者在运行时定义和管理事件的响应&#xff0c;从而实现松耦合的事件处理。 以下是UnityEvent的一些主要特点和用途&#xff1a; 松耦合的设计&#xff1a;UnityEvent允许对象之间…...

食品安全管理员考试真题题库及答案

食品安全管理员考试真题题库及答案 95.对食品生产经营企业来说&#xff0c;实施ISO 22000是&#xff08;&#xff09;。 A.强制性的 B.无效的 C.自愿的 D.必须的 答案&#xff1a;C 96.CDC的意思是&#xff08;&#xff09;。 A.卫生监督所 B.疾病控制预防中心 C.卫生…...

【C++】—— vector 的模拟实现

【C】—— vector 的模拟实现 0 前言1 vector 的成员变量1.1 stl 库中的 vector 成员变量1.2 模拟实现 vector 成员变量 2 迭代器3 size、capacity、empty4 opreator[ ]5 reserve5.1 初版 reserve5.2 _finish 的处理5.3 深拷贝5.4 终版 6 push_back 与 pop_back7 打印函数7.1 初…...

MySQL 查询过慢的优化方法

1. 优化查询语句 问题&#xff1a;使用 SELECT * 会导致查询获取不必要的数据。 SELECT * FROM users WHERE age > 30;优化建议&#xff1a; 指定需要的列&#xff0c;这样可以减少数据传输的负担&#xff0c;提升查询速度。 SELECT name, email FROM users WHERE age &g…...

YoloV8修改分类(Classify)的前处理(记录)

修改原因 yolo自带的分类前处理对于长方形的数据不够友好&#xff0c;存在特征丢失等问题修改后虽然解决了这个问题但是局部特征也会丢失因为会下采样程度多于自带的&#xff0c;总之具体哪种好不同数据应该表现不同我的数据中大量长宽比很大的数据所以尝试修改自带的前处理&a…...

半监督学习能否帮助训练更好的模型?

数据科学家面临的最常见挑战之一是缺乏足够的标记数据来训练一个可靠且准确的模型。标记数据对于监督学习任务&#xff0c;如分类或回归至关重要。然而&#xff0c;在许多领域&#xff0c;获取标记数据既昂贵又耗时&#xff0c;有时甚至是不切实际的。另一方面&#xff0c;未标…...

VBA 获取字段标题代码轻松搞定

hi&#xff0c;大家好&#xff01; 最近又有一段时间没和大家唠嗑了&#xff0c;最近也没有时间给大家开直播&#xff0c;天天忙&#xff0c;但不知道在忙啥&#xff01;那今天我们来讲点啥好玩的呢&#xff1f; 今天是老师节&#xff0c;那就先祝各位老师节日快乐&#xff0…...

C++代码片段

for(int i1; i<shuliang; i) { int f100; cout<<a[i].name<<":"<<\n; cout<<"该舰艇现在距离基地"<<km<<"km&#xff0c;需要"<<km…...

Golang | Leetcode Golang题解之第388题文件的最长绝对路径

题目&#xff1a; 题解&#xff1a; func lengthLongestPath(input string) (ans int) {n : len(input)level : make([]int, n1)for i : 0; i < n; {// 检测当前文件的深度depth : 1for ; i < n && input[i] \t; i {depth}// 统计当前文件名的长度length, isFi…...

docker打包前端项目

&#x1f389; 前言 之前有出过一期打包后端项目和数据库的教程&#xff0c;现在填个坑&#xff0c;出一期打包前端项目的教程&#xff0c;废话不多说&#xff0c;我们直接进入正题。 &#x1f389; 编写Dockerfile文件 老规矩&#xff0c;先描述项目结构&#xff0c;结构图…...

调度器怎么自己写?调度器在实现时需要注意哪些细节?请写一个jvm的调度器?如何在这个调度器中添加多个任务?

如果你想自己编写一个调度器&#xff0c;可以按照以下步骤进行&#xff1a; 一、确定需求和目标 明确调度器的应用场景&#xff0c;例如任务调度、资源分配、进程管理等。 确定调度的对象&#xff0c;比如任务、作业、进程等。 定义调度的目标&#xff0c;如最小化完成时间、最…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...