news 2026/5/5 18:44:29

拒绝 CRUD!Spring Boot + Vue3 打造“亿级并发”电商秒杀系统:Redis Lua + RabbitMQ 削峰填谷实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
拒绝 CRUD!Spring Boot + Vue3 打造“亿级并发”电商秒杀系统:Redis Lua + RabbitMQ 削峰填谷实战

💥 前言:数据库不是许愿池

很多新手做秒杀,逻辑是这样的:

  1. 用户点击 -> 2. 查询数据库库存 -> 3. 如果库存 > 0 -> 4. 减库存,生成订单。

在并发只有 10 的时候,没问题。
但在并发 10 万的时候,MySQL 会瞬间死锁、CPU 飙升 100%,整个系统宕机。

要实现“亿级并发”(虽然我们只有一台破电脑,但架构要向那个方向设计),必须遵循一个原则:把数据库当大爷供着,尽量别烦它。


🏗️ 一、 架构设计:漏斗模型

秒杀的本质是**“限流”“异步”**。

流量漏斗图 (Mermaid):

异步削峰

1. 拦截重复请求
2. 读缓存 (10W QPS)
3. 发送秒杀成功消息
4. 匀速消费 (1000 QPS)
5. 最终落地

海量用户 (100W QPS)

Nginx / CDN

Redis (Lua 脚本扣减库存)

RabbitMQ (削峰填谷)

后端消费者

MySQL 数据库


🚀 二、 第一道防线:Redis + Lua 实现原子扣减

Redis 是单线程的,速度极快。但如果我们分两步操作(先 Get 库存,再 Decr 扣减),在高并发下依然会有线程安全问题(超卖)。

这时候,Lua 脚本登场了。它能保证多条 Redis 命令像一条命令一样原子执行

1. 编写 Lua 脚本 (seckill.lua)
放在src/main/resources下:

-- 参数 KEYS[1]: 商品库存 Key-- 参数 ARGV[1]: 购买数量 (通常是 1)localstock=tonumber(redis.call('get',KEYS[1]))-- 如果库存不存在或小于购买数量,返回 -1if(stock==nil)or(stock<tonumber(ARGV[1]))thenreturn-1end-- 扣减库存redis.call('decrby',KEYS[1],tonumber(ARGV[1]))return1-- 成功

2. Spring Boot 调用 Lua

@AutowiredprivateStringRedisTemplateredisTemplate;publicbooleanseckill(StringuserId,StringgoodsId){// 1. 预加载 Lua 脚本DefaultRedisScript<Long>redisScript=newDefaultRedisScript<>();redisScript.setScriptSource(newResourceScriptSource(newClassPathResource("seckill.lua")));redisScript.setResultType(Long.class);// 2. 执行脚本 (原子操作)Longresult=redisTemplate.execute(redisScript,Collections.singletonList("seckill:stock:"+goodsId),"1");// 3. 判断结果if(result!=null&&result==1){// 抢单成功!但这只是在 Redis 里成功了returntrue;}returnfalse;}

这一步,我们挡住了 99% 的流量。只有库存数量的人能通过。


🌊 三、 第二道防线:RabbitMQ 削峰填谷

即使通过了 Redis,如果瞬间有 1 万个“成功”请求同时打向 MySQL 去创建订单,数据库一样会挂。
我们需要一个蓄水池—— RabbitMQ。

1. 生产者:发送消息 (Controller 层)

if(redisService.seckill(userId,goodsId)){// Redis 扣减成功后,不直接操作数据库,而是发个消息SeckillMessagemessage=newSeckillMessage(userId,goodsId);rabbitTemplate.convertAndSend("seckill_exchange","seckill_route",message);returnResult.ok("排队中...");// 立即返回给前端,不让用户等}else{returnResult.error("秒杀结束");}

2. 消费者:慢慢处理 (Service 层)

消费者可以根据数据库的能力,设置Qos(预取数量),例如每次只取 50 条处理,慢慢写入 MySQL。

@RabbitListener(queues="seckill_queue")publicvoidreceive(SeckillMessagemessage){// 1. 再次判断数据库库存 (防止 Redis 和 DB 数据不一致)Goodsgoods=goodsMapper.getGoods(message.getGoodsId());if(goods.getStock()<=0){return;}// 2. 创建订单 & 扣减真实库存// 这一步必须加事务orderService.createOrder(message.getUserId(),message.getGoodsId());}

🎨 四、 前端 Vue3 的配合:把压力留在浏览器

后端再强,也怕前端疯狂F5刷新。前端需要做两件事:

  1. 按钮置灰:点击“立即秒杀”后,按钮立刻 Disable,防止用户连点。
  2. 答题/验证码:在点击前强制用户进行图形验证或算术题,拉长用户请求的时间差。
  3. 轮询结果:因为后端返回的是“排队中”,前端需要每隔 2 秒轮询一次接口,查询订单是否创建成功。
// Vue3 伪代码consthandleSeckill=async()=>{btnDisabled.value=true;// 1. 禁用按钮constres=awaitapi.startSeckill(goodsId);if(res.code===200){// 2. 进入轮询状态startPollingResult();}else{message.error("抢光了!");btnDisabled.value=false;}}

🛡️ 五、 总结与进阶

通过这套架构,我们实现了:

  1. Redis Lua:原子性扣减,防止超卖,抗住高并发读。
  2. RabbitMQ:异步下单,削峰填谷,保护脆弱的 MySQL。
  3. Vue3:前端限流,优化用户体验。

如果真的有“亿级”并发,还需要做什么?

  • 服务降级 (Sentinel):流量实在太大,直接熔断非核心业务。
  • 分库分表:订单表数据量太大,需要 Sharding。
  • CDN 静态资源缓存:把 CSS/JS/图片全部推到边缘节点。

Next Step:
别光看,去你的 IDE 里建两个 Spring Boot 项目(一个发消息,一个收消息),装个 Docker 版的 Redis 和 RabbitMQ,亲自跑通这个流程。面试时,这绝对是你的杀手锏

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/3 6:35:46

提示词语法详解:在SD中正确调用lora-scripts生成的LoRA模型

提示词语法详解&#xff1a;在SD中正确调用lora-scripts生成的LoRA模型 在数字内容创作日益个性化的今天&#xff0c;如何让AI真正“理解”你的风格&#xff0c;成为每一位创作者关心的问题。无论是想复现某位艺术家的笔触、还原某个虚拟角色的形象&#xff0c;还是打造专属品…

作者头像 李华
网站建设 2026/5/3 4:18:12

C++多线程编程避坑宝典(死锁预防的8个黄金法则)

第一章&#xff1a;C多线程死锁问题的根源剖析在C多线程编程中&#xff0c;死锁是导致程序停滞不前的常见问题。其根本原因在于多个线程对共享资源的竞争访问缺乏合理的同步控制&#xff0c;导致彼此相互等待对方释放锁&#xff0c;从而陷入永久阻塞状态。死锁的四大必要条件 互…

作者头像 李华
网站建设 2026/5/1 15:31:06

C++26契约编程新特性:如何利用静态/动态检查提升代码健壮性

第一章&#xff1a;C26契约编程概述C26 引入的契约编程&#xff08;Contract Programming&#xff09;机制旨在提升代码的可靠性与可维护性&#xff0c;通过在函数接口中显式声明前置条件、后置条件和断言&#xff0c;使程序逻辑更加清晰&#xff0c;并为编译器和运行时系统提供…

作者头像 李华
网站建设 2026/5/3 8:33:57

C++内核优化实战案例:一个循环优化让系统吞吐量提升7倍

第一章&#xff1a;C内核性能优化的挑战与机遇在现代高性能计算、实时系统和资源受限环境中&#xff0c;C 内核的性能优化成为决定系统成败的关键因素。尽管 C 提供了对硬件的精细控制和高效的执行能力&#xff0c;但充分发挥其潜力仍面临诸多挑战&#xff0c;同时也蕴藏着巨大…

作者头像 李华
网站建设 2026/5/4 3:57:02

【C++26任务队列深度解析】:揭秘新标准中队列大小控制的5大核心机制

第一章&#xff1a;C26任务队列大小控制的演进与意义随着并发编程在现代软件系统中的广泛应用&#xff0c;任务调度机制的可控性与稳定性成为关键设计考量。C26标准在并发设施方面引入了对任务队列大小的显式控制机制&#xff0c;标志着标准库在线程池与异步执行模型上的进一步…

作者头像 李华
网站建设 2026/5/3 5:34:12

C++26反射即将上线:5个代码示例带你提前掌握未来标准

第一章&#xff1a;C26反射特性概览C26 正在为现代 C 引入原生反射支持&#xff0c;这标志着语言在元编程能力上的重大飞跃。通过编译时反射&#xff0c;开发者能够直接查询和操作类型、变量、函数等程序结构的信息&#xff0c;而无需依赖宏或复杂的模板技巧。核心目标与设计原…

作者头像 李华