【常用解决方案系列】如何设计一个稳定可靠的秒杀系统

915 阅读4分钟

  商品秒杀在业务运营中是一个很常见的营销手段,运营方通常拿出少量的爆款商品,以很低的价格(1元秒杀iphone12),进行秒杀售卖,加上秒杀前的广告宣传,如此操作,势必短时间内会吸引大量用户过来秒杀,这类系统一般有如下特点:

  • 高并发
  • 请求量远远大于库存量

  那如何保证秒杀业务的正常进行呢?作为研发人员,在设计之初就要考虑好系统的稳定性,可靠性,能不能支撑住大流量请求?如何防止库存超卖?如何防止恶意外挂请求?如何避免其他服务受到牵连?

秒杀系统基本设计原则

  • 层层拦截,尽量拦截流量在上游
    • 尽量放入少量请求去扣减库存,多者无益,(10个库存,放入10000个请求,没有意义的)
  • 充分利用缓存
    • 利用缓存读多写少的特性,来扛住大流量
  • 利用异步消息队列
    • 削峰填谷

秒杀系统设计七要素

  • 限流

    ​ 秒杀活动中,接口的请求量会是平时的数百倍甚至数千倍,从而有可能导致接口不可用,并引发连锁反应导致整个系统崩溃,甚至有可能会影响到其它服务。不能放入大量请求到服务端,需考虑限流(具体可参见:blog.csdn.net/qq_26977063… )

    • Nginx限流
    • 应用限流( tomcat 限流)
    • API限流
    • 分布式限流组件 sentinel ,OpenResty
  • 削锋

    • 排队
      • 基于消息
      • 提交后,搞一个倒计时,排队提交请求
    • 答题
      • 复杂验证码+时间控制
      • 提交答案,缓存2-10s出结果,避免重复请求,参考12306购票系统
    • 分层过滤
      • CDN->前台读系统(商品详情系统)->后台写系统(交易系统)->DB
      • 每层设置一定过滤条件
  • 异步

    • 消息队列
  • 缓存

    • 分布式缓存
    • 分布式锁
  • 可扩展

    • 加机器+平滑扩容
  • 独立部署

    • 目的:解耦合,防止“城门失火,殃及池鱼!”
  • 压测

    • 知晓系统性能指标,实时监控+告警

    • 明确系统瓶颈,及时平滑扩容

秒杀系统常见解决方案

  • 前端

    • 页面静态化+CDN

      • 动静分离

        • 静态数据缓存

          • 用户浏览器

          • CDN

          • cache

      • 动态数据

        • 异步JS请求
        • 二级缓存
        • CDN
        • 物理机部署
      • 热点数据提前缓存

        • 基于访问埋点,提前找出热点商品,设置LRU策略
        • 业务上选,如提交报名秒杀商品
        • 二八原则
    • 页面防重复提交

      • 提交即置灰
      • JS层面,限制用户在x秒之内只能提交一次请求 如此限流,80%流量已拦。
    • 用户限流

      • 同一时间,同一ip,限制提交次数
    • 活动链接参数化

      • 防止URL提前泄露
      • 基于时间戳做加密链接,时间到了,才可以访问
  • 后端

    • 网关层

      • 限制UID访问频率
        • IP
      • 接口限流
        • 同一个uid,限制访问频度,做页面缓存,x秒内到达站点层的请求,均返回同一页面
        • 同一个item的查询,例如手机车次,做页面缓存,x秒内到达站点层的请求,均返回同一页面 如此限流,又有99%的流量会被拦截在站点层
    • 服务层

      • 秒杀信息缓存,库存缓存

        • 基础信息提前缓存起来,避免直接查询DB
      • 用户合法性校验

        • 资格校验 ,利用规则剔除不符合用户,如VIP会员可参与
        • 考虑下游接口性能,防止拖垮下游
      • 秒杀结束,缓存标记

        • 结束标签缓存起来,秒杀完成后,后续请求直接返回秒杀失败
      • 预冻结库存,库存<=0,秒杀结束,置为结束

        • 库存扣减,保证原子操作(decr )
        • lua脚本
      • 判断是否秒到,秒到则结束

      • 预秒杀到的UID,通过消息队列去排队下单

      • 真正秒杀开始:校验商品,库存,用户是否秒到,加锁去下单

      • 优化

        • 秒杀接口隐藏,避免直接暴露,防外挂
          • 用户点击秒杀按钮的时候,根据用户id生成唯一的加密串存入缓存并返回给客户端,然后客户端再次请求的时候带着加密串过来,后端进行校验是否合法,若不合法,直接返回请求非法;
          • token机制
            • UID

            • client info

            • 时间戳

    • DB层(脆弱)

      • 秒杀库存表(乐观锁)
      • version
      • stock > 0
      • 秒杀订单表(uId,商品Id,联合唯一索引)
  • 部署

    • 秒杀业务单独部署一套
      • 避免其他业务受影响
    • 业务降级
      • 参考:双11退款业务降级 不可用

​    以上是常见秒杀系统设计的基本思路,具体使用可以结合具体业务,流量大小来选取不同的解决方案。