redis--011

一、传统秒杀痛点

原始流程全部压力落在 MySQL:查询库存、判断用户是否下单、扣库存、创建订单,大量并发请求直接打数据库,MySQL 扛不住高并发。

二、Redis 优化整体架构

  1. Nginx:接收前端大量请求,做负载均衡。
  2. Redis 层(Lua 脚本)库存校验、一人一单校验、扣减库存、记录已下单用户,全部在 Redis 内部原子完成,拦截绝大部分无效请求。
  3. 阻塞队列 :Redis 校验成功后,把优惠券ID、用户ID丢入阻塞队列,直接给前端返回订单 ID。
  4. 异步消费者:后台线程从队列取出消息,异步操作 MySQL 完成真正的创建订单、扣数据库库存。

核心思想:Redis 做前置校验过滤流量,数据库异步慢处理,把高并发挡在 Redis,保护 MySQL。

三、Lua 脚本作用

Redis 单线程执行 Lua 脚本,整个脚本具备原子性,中间不会被其他命令打断,避免超卖、重复下单并发问题。

Lua 脚本业务逻辑

输入参数:voucherId优惠券IDuserId用户ID

  1. 判断库存:读取seckill:stock:{voucherId}库存值
    • 库存≤0 → 返回1,代表库存不足
  2. 判断用户是否已经抢购过:使用 Set 集合seckill:order:{voucherId}保存已下单用户 ID
    • sismember判断用户已存在 → 返回2,代表重复下单
  3. 校验全部通过:
    • incrby对库存 key 做 - 1 扣减库存
    • sadd把 userId 写入 Set 集合标记该用户已下单
    • 返回0,代表校验成功,可以下单

返回码含义

表格

返回值 含义
0 校验通过,允许下单,进入异步队列
1 库存不足
2 用户重复下单(一人一单限制)

四、完整业务执行流程

  1. 用户发起秒杀请求,进入服务。
  2. Java 调用 Redis 执行 Lua 脚本。
  3. 判断脚本返回结果:
    • 返回1/2:直接向前端返回失败提示。
    • 返回0:把业务数据放进阻塞队列,立刻返回订单 ID 给前端。
  4. 后台独立线程不断消费阻塞队列:
    • 查询数据库
    • 扣减 MySQL 真实库存
    • 创建订单记录
相关推荐
努力努力再努力wz3 小时前
【Redis入门系列】:从 RESP 协议到 redis-plus-plus:Redis 客户端编程与 C++ 接口设计
开发语言·数据库·c++·redis·分布式·缓存·架构
JavaPub-rodert1 天前
Redis 和 MySQL 如何保证数据一致性?从业务方案到底层原理完整讲解
数据库·redis·mysql
程序员阿明1 天前
spring boot4+springAI 2加redis多轮对话存储
spring boot·redis·后端
莫得感情 o2 天前
Redis 05 · 持久化:RDB 与 AOF 怎么保证数据不丢
redis·缓存
curd_boy2 天前
【Redis】Redis从缓存到AI向量平台
人工智能·redis·缓存
莫得感情 o2 天前
Redis 02 · 数据结构:String 到 Stream 怎么选
redis
devpotato2 天前
缓存与数据库更新顺序不一致问题
java·数据库·redis
NeverFear7922 天前
【黑马点评】短信登录
java·redis·tomcat·intellij-idea
攻城有术2 天前
专项攻克——重写 Redis 依赖包方法的 6 种实现方式
java·数据库·redis·bootstrap