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

秒杀系统的常用架构是什么?怎么设计?

架构

秒杀系统需要单独部署,如果说放在订单服务里面,秒杀的系统压力太大了就会影响正常的用户下单。
在这里插入图片描述
常用架构:
在这里插入图片描述

Redis 数据倾斜问题

第一步扣减库存时

假设现在有 10 个商品需要秒杀,正常情况下,这 10 个商品应该均匀的分布在 Redis 集群的每个主节点上。商品是通过下图的算法通过商品 id 计算出自己应当在哪个分片并定位到 Redis 的,但是可能由于分片算法不太均匀,导致这 10 个商品都落到了某一个节点上去。

解决:因此我们需要给 Redis 的 key 加一个 hashtag:{redis1},这样 Redis 计算分片时就会用 {} 里的数据来计算。
在这里插入图片描述

依旧会有问题(热点 key 问题):假设商品 1 非常火爆,10w 个请求都去秒杀商品 1 ,就会导致其对应的 Redis 扛不住压力。

解决:像这种热门商品应当有预判(如:原价 2000 的商品现在只要 500),提前将该商品的库存均匀的分片在多个 Redis 主节点上。当第一个请求进入时,先判断该商品是不是热点商品,如果是,请求第一个分片。当第二个请求进入时,先判断该商品是不是热点商品,如果是,请求第二个分片。

MQ 消息丢失问题

第二步,扣减库存后,将订单消息发送到 MQ

不同的 MQ 解决方案不同,一个简单通用的方案是:加一张消息发送表,先在消息发送表中记录“待处理”然后再给 MQ 发消息,消费者(下单服务)收到消息生成完订单后,回调发送者(抢购服务)将记录改为“已处理”。

设置一个定时任务,隔一段时间去扫描消息发送表,如果发现有消息一直没有被处理,消息很有可能丢失了,那就重发该消息。但是这种方案可能导致消息的重复发送,消费者需要做幂等处理。
分布式事务方案 – 最终一致性,seata 比较重,很多中小型公司采用这种方案

分布式事务方案 – 最终一致性,seata 比较重,很多中小型公司采用这种方案

消费者如何做幂等处理?

  1. 如果消费者收到消息时,订单号已经生成了,那只需要判断一下该订单号是否存在即可
  2. 如果消费者收到消息时没有订单号,订单号是消费者处理消息时通过一些算法(雪花)生成的,就不能直接判断订单号是否存在。
    • 可以生成一个标识唯一消息的业务 id
    • 可以在下单逻辑处理的第一行代码加上一把分布式锁。直接用 Redis 实现,执行 setnx 命令,关键在于 key 的设计。setnx(userId + productId, value),同一个用户秒杀同一件商品 key 是一样的。

MQ 消息积压怎么解决?

生产者的生产速度远远大于消费者的消费速度,就会导致 MQ 消息积压。

  1. 增加消费者数量
  2. 增加消息队列的容量
    依旧有可能消息积压,因为 Redis 扣减库存的速度比数据库高几个量级。

解决:假设消费者拿到一条消息,先判断消息的发送时间,如果这条消息的发送时间和当前时间已经超过了一个阈值(1 分钟),那么就认为出现了消息积压,则将这些消息直接放入 Redis。用户查询订单信息会先查 Redis,再查数据库,在 Redis 查到就可以直接返回了。

该消息最终还是得同步到数据库中生成订单,同步完后再从 Redis 里面删除。
在这里插入图片描述

如果说超时了太久依旧没有被处理,就直接丢弃掉该消息,提示用户下单失败。

Redis 集群崩溃了如何保证高可用?

  1. 操作 Redis 时网络不稳定出现瞬断 – 降级
    在减库存代码上套一层 try-catch,在 catch 里面重试 1、2 次
    在这里插入图片描述
  2. 如果网络瞬断比较长或者 Redis 集群真的崩溃了 – 本地缓存
    解决:在抢购服务设置一个本地高速缓存 rocksDB,将下单请求临时存到 rocksDB 里面。然后设置一个定时任务定时去扫描这个缓存,将下单请求重新发送到 Redis 里面。(前提是 Redis 集群能够快速恢复)
    在这里插入图片描述

库存超卖

主节点扣减库存成功了,但是在同步到从节点前主节点宕机了,从节点被选为了新的主节点,Redis 与数据库数据也不一致了。

  1. 将 Redis 主从异步同步改为同步同步
  2. 不使用 Redis 主从,只用 Redis 集群
  3. 数据库的数据已经为 0 了生成订单不成功

回答:

  1. 使用并发控制来确保扣减的原子性 — 影响性能
  2. 在高并发场景下,可以将库存提前预热到 Redis 中,利用 Redis 的原子操作指令扣减库存,后续对于库存的扣减只操作 Redis
  3. 如果某个商品的访问量比较大,我们可以对这个商品的库存进行拆分,把不同的库存放进不同的库里面,后续对单个数据加锁
http://www.lryc.cn/news/543977.html

相关文章:

  • 【文件基础操作】小笔记
  • RabbitMQ系列(七)基本概念之Channel
  • 本地搭建Koodo Reader书库结合内网穿透打造属于自己的移动图书馆
  • DeepSeek R1 训练策略4个阶段解析
  • 【博资考4】网安学院-硕转博考试内容
  • 30 分钟从零开始入门 CSS
  • C语言综合案例:学生成绩管理系统
  • 使用python做http代理请求
  • 数据库事务的基本要素(ACID)
  • DeepSeek R1满血+火山引擎详细教程
  • 大型语言模型技术对比:阿里Qwen qwq、DeepSeek R1、OpenAI o3与Grok 3
  • ArcGIS Pro可见性分析:精通地形视线与视域分析
  • 计算机工具基础(五)——Vim
  • Android应用app实现AI电话机器人接打电话
  • Mobaxterm服务器常用命令(持续更新)
  • Android14窗口管理自适应投屏分辨率
  • Shot Studio for macOS 发布 1.0.2
  • 《深度学习实战》第4集:Transformer 架构与自然语言处理(NLP)
  • Starrocks入门(二)
  • 银河麒麟高级服务器操作系统在线调整/pro/{PID}/limits文件中nofile的软限制和硬限制参数值操作方法
  • html css js网页制作成品——HTML+CSS甜品店网页设计(5页)附源码
  • Open WebUI项目源码学习记录(从0开始基于纯CPU环境部署一个网页Chat服务)
  • 【Python 入门基础】—— 人工智能“超级引擎”,AI界的“瑞士军刀”,
  • 蓝桥杯练习代码
  • Imagination通过最新的D系列GPU IP将效率提升至新高度
  • C高级——shell(3)
  • 【C语言】第八期——指针、二维数组与字符串
  • docker 运行claude 的computer use
  • JAVA面试_进阶部分_23种设计模式总结
  • 边缘计算收益低的三大指标