分布式秒杀系统的设计

偏执的太偏执、 2022-10-26 14:16 308阅读 0赞

分布式秒杀系统的设计

前言

不知道你在面试的过程中有没有被问到如何设计一个分布式秒杀系统?本篇博客根据大神们的梳理的体系并结合自己实际的项目经验,大致描述我们在设计分布式秒杀系统需要关注的核心内容——分布式锁、分布式限流、消息队列等等,希望可以帮助同学们可以在面试中更加从容地回答这个问题。

正文

分布式秒杀系统的设计

秒杀系统的核心的问题

  • 并发读:核心的优化理念是减少用户到服务端来“读”数据,或者让他们读更少的数据;
  • 并发写:要求在数据库层面独立出一个库,做特殊处理,可以理解为为秒杀设计专门的表,精简表字段。

秒杀系统的的基本要求:

  • 高性能:涉及大量并发读写,可以从缓存、消息队列、 请求削峰等角度进行设计
  • 一致性:保证秒杀减库存中的数据一致性。
  • 高可用:保证系统的高可用和正确性,设计PlanB进行兜底。

架构原则(4要1不要):

  • 数据要尽量少:用户请求与响应的数据尽可能得少,可以减少数据序列化与反序列化的性能损耗;
  • 请求数要尽量少:减少或者合并css/java script、图片,以及Ajax请求等,TCP三次握手,DNS解析等都会有资源消耗;
  • 路径要尽量短:用户发出请求到返回数据这个过程中,需求经过的中间的节点数尽可能少,尽可能使用RPC调用,提升系统性能;
  • 依赖要尽量少:依赖,指的是要完成一次用户请求必须依赖的系统或者服务;
  • 不要有单点:无论是系统资源还是数据资源在设计的时候一定要考虑冗余。

根据上述的,可以设计如下:

在这里插入图片描述

秒杀系统的实现:

  • 分布式限流:采用sentinel的方式进行分布式限流,诸如warm up(预热)、拒绝、匀速排队等手段;
  • 负载均衡:对系统进行微服务化,拆分成商品中心、用户中心、订单中心;
  • 缓存的使用:对热点数据(遵循二八原则)并且对实时性要求不高的数据进行缓存处理,如商品的基本信息;
  • 消息队列的使用:针对可以异步处理的操作,如下单,采用消息队列的方式进行处理, 实行流量削峰;
  • 分布式锁:进行抢购时采用分布式锁的方式保证不会出现“超卖现象”;

如何防止“超卖”现象

秒杀系统防止的“超卖”的关键在于减库存的方式,通常有三种:

  • 下单减库存:一定不会出现超卖情况,但是有些人下单完不付款会影响其他人。
  • 付款减库款:付款减库存,可能会因为并发高导致付款时已经卖光,付不了款。
  • 预扣库存:最常用,如下单后扣库存,保留十分钟,在十分钟内未付款就不保留。如果付款时发现库存不足则不允许付款。

预扣库存,存在“黄牛抢单”恶意抢单的情况,可以通过信誉积分、设置最大购买数、已有未支付订单不允许再次下单等方式进行控制,预扣库存通常使用分布式锁来实现的。

技术方案:

  • 采用setnx的方式实现分布式锁,在获取锁,进行查库存 -> 创建订单 -> 扣减库存(并不会对库存数量进行上锁),这种方案将实现请求的序列化,但是并发量有限
  • 采用分段锁的方式进行抢购,可以借鉴LongAdder的实现,通过订购时随机分配一个分段锁,如果该分段库存不足,要自动释放锁,切换到一下分段库存尝试获取锁。
  • 分布式锁不会保存库存数量,获取锁只是获取购买销售品的资格,库存数量由数据库控制。

如解决订单过期库存回库问题

解决订单过期库存回库的潜在方案:

  • 使用后台线程不断扫描数据库,性能极低,弃用
  • 将订单数据存入Redis中并设置失效时间,考虑到要保留订单信息,弃用
  • 使用delayedQueue延时队列,设置到期时间,其中的对象只能在到期时才能从队列中取走,进行过期操作,但是不支持分布式,弃用
  • 使用分布式定时任务去处理相关订单,但是时间间隔难以设置,并且数据量巨大,慎用
  • 使用RabbitMQ延迟队列来实现,并使用定时任务处理可能的消息丢失导致的库存无法释放,采用

如何解决用户重复订购问题

用户重复订购可以理解为请求幂等性的实现:

  • 使用数据库唯一键,在锁座表中,设定场次Id和座位Id作为唯一键。锁定座位时,如果座位已经售卖,会报出数据库异常,不允许某一个座位重复售卖。
  • 基于Redis来实现,使用set操作具有天然的幂等性,当业务处理完再删除对应的key
  • 通过先查一次数据,来判断是新增操作还是更新操作
  • 通过向数据库前置一个布隆过滤器来判断数据是新数据还是旧数据,再使用主键索引来实现
  • 使用状态机来保证幂等性,订单状态可以有初始化、订购中、订购失败、订购成功,从而限制重复订购
  • 对于前端的订单采用token幂等性校验,防止重复点击或者网络原因导致重复提交,外部接口的请求采用外部订单号做幂等性校验
  • 借助消息队列的串行化,借助第三方的幂等性校验,也能保证我们业务上的幂等性

关于系统的设计中涉及的技术可移步:

  • 分布式锁可参考我的博客:从悲观锁、乐观锁到分布式锁
  • 负载均衡等分布式知识可参考我的博客:溪源的Java笔记—分布式
  • 消息队列可参考我的博客:溪源的Java笔记—消息队列
  • 分布式限流可参考我的博客:高并发之限流算法
  • springboot实现商品秒杀功能可参考我的博客:springboot实现商品秒杀功能

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,308人围观)

还没有评论,来说两句吧...

相关阅读

    相关 设计一个系统-方案分析

    学习使用,老鸟飞过,欢迎交流 秒杀系统应该考虑哪些因素 高可用:秒杀系统最大的特点就是并发高,在极短的时间内, 瞬间用户量大。试想一下双11的时候可能会有几十万的用户去

    相关 系统架构设计

    秒杀系统的架构设计 秒杀系统,是典型的短时大量突发访问类问题。对这类问题,有三种优化性能的思路: 写入内存而不是写入硬盘 异步处理而不是同步处理 分布式处理