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

news/2025/3/5 11:47:21/

架构

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

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.ppmy.cn/news/1576807.html

相关文章

FFmpeg-chapter3和chapter4-读取视频流(原理篇和实战篇)

ffmpeg网站:About FFmpeg 1 库介绍 (1)libavutil是一个包含简化编程函数的库,包括随机数生成器、数据结构、数学例程、核心多媒体实用程序等等。 (2)libavcodec是一个包含音频/视频编解码器的解码器和编…

Linux驱动开发-字符设备驱动开发

Linux驱动开发-字符设备驱动开发 一,Linux驱动开发二,字符设备驱动开发1.具体实现2.1.1驱动模块具体函数实现2.1.2 应用调试模块具体函数实现2.1.3 Makefile2.1.4 进行测试2.1.4.1创建节点2.1.4.2 加载和卸载驱动模块2.1.4.3 测试 2.字符设备驱动应用程序…

【51单片机】程序实验13.串口通信

主要参考学习资料:B站【普中官方】51单片机手把手教学视频 开发资料下载链接:http://www.prechin.cn/gongsixinwen/208.html 前置知识:C语言 单片机套装:普中STC51单片机开发板A4标准版套餐7 目录 通信的基本概念串行通信与并行通…

游戏引擎学习第134天

仓库:https://gitee.com/mrxiao_com/2d_game_3 回顾 到目前为止,由于我们专注于古代游戏的开发,我们还没有深入思考资源应该如何存储以及在最终版本中如何高效管理。因此,在完成游戏的基本框架之前,我们必须先决定如何存储这些资…

使用300M带宽是否可以流畅地玩原神

本文来自腾讯元宝 ps:搬家了,需要装个路由器打游戏。 根据搜索结果,300M的网络带宽完全可以满足《原神》的流畅游玩需求。以下是具体分析及优化建议: 一、带宽需求与300M网络的适配性 ​带宽要求较低​ 《原神》作为一款开放世界…

stable-diffusion-webui 加载模型文件

背景 stable-diffusion-webui 安装完毕后,默认的模型生成的效果图并不理想,可以根据具体需求加载指定的模型文件。国内 modelscope 下载速度较快,以该站为例进行介绍 操作步骤 找到指定的模型文件 在 https://modelscope.cn/models 中查找…

ArcGIS操作:13 生成最小外接矩阵

应用情景:筛选出屋面是否能放下12*60m的长方形,作为起降场候选点(一个不规则的形状内,判断是否能放下指定长宽的长方形) 1、面积初步筛选 Area ≥ 720 ㎡ 面积计算见 2、打开 ArcToolbox → Data Management Tools …

centos和ubunt下安装redis

1,判断环境是否有gcc gcc --version 如果未安装则执行 yum install -y gcc tcl 2,安装包下载 cd /usr/local mkdir redis wget https://download.redis.io/releases/redis-4.0.11.tar.gz tar -xvf redis-4.0.11.tar.gz cd redis-4.0.11.tar.gz 编译 mak…