CSDN双十一的秒杀场景是如何设计的?( 二 )

  1. 页面静态化 , 参与秒杀活动的商品一般都是已知的 , 可以针对活动页面做静态化处理 , 缓存到CDN 。 假设我们一个页面300K大小 , 1千万用户的流量是多少?这些请求要请求后端服务器、数据库 , 压力可想而知 , 缓存到CDN用户请求不经过服务器 , 大大减小了服务器的压力 。
  2. 活动预热 , 针对活动的活动库存可以独立出来 , 不和普通的商品库存共享服务 , 活动库存活动开始前提前加载到redis , 查询全部走缓存 , 最后扣减库存再视情况而定 。
  3. 独立部署 , 资源充足的情况下可以考虑针对秒杀活动单独部署一套环境 , 这套环境中可以剥离一些可能无用的逻辑 , 比如不用考虑使用优惠券、红包、下单后赠送积分的一些场景 , 或者这些场景可以活动结束后异步的统一发放 。 这只是一个举例 , 实际上单独针对秒杀活动的话你肯定有很多无用的业务代码是可以剥离的 , 这样可以提高不少性能 。
经过这两步之后 , 最终我们的流量应该是呈漏斗状 。

CSDN双十一的秒杀场景是如何设计的?
本文插图
超卖秒杀除开高并发高流量下的服务稳定性之外 , 剩下的核心大概就是怎么保证库存不超卖了 , 也可以说要保证的是最终一致性 。 一般来说 , 针对下单和库存有两种方式:
  1. 下单即扣库存 , 这是最常规的大部分的做法 。 但是可能在活动中会碰到第二点说到的情况 。
  2. 支付完成扣库存 , 这种设计我碰到过就是酒店行业 , 廉价房放出来之后被黄牛下单抢占库存导致正常用户无法下单 , 然后黄牛可以用稍高的价格再售卖给用户从中牟利 , 所以会有在一些活动的时候采取支付成功后才占用库存的做法 。 不过这种方式实现起来比较复杂 , 可能造成大量的无效订单 , 在秒杀的场景中不太适用 。
针对秒杀建议选择下单扣库存的方式 , 实现相对简单而且是常规做法 。
方案:

CSDN双十一的秒杀场景是如何设计的?
本文插图
  1. 首先查询redis缓存库存是否充足
  2. 先扣库存再落订单数据 , 可以防止订单生成了没有库存的超卖问题
  3. 扣库存的时候先扣数据库库存 , 再扣减redis库存 , 保证在同一个事务里 , 无论两者哪一个发生了异常都会回滚 。 有一个问题是可能redis扣成功了由于网络问题返回失败 , 事务回滚 , 导致数据库和缓存不一致 , 这样实际少卖了 , 可以放到下轮秒杀去 。
这种做法能一定程度上解决问题 , 但是也有可能会有其他问题 。 比如当大量请求落在同一条库存记录上去做update时 , 行锁导致大量的锁竞争会使得数据库的tps急剧下降 , 性能无法满足要求 。 另外一种做法就是排队 , 在服务层进行排队 , 针对同一个商品ID的也就是数据库是一条库存记录的做一个内存队列 , 串行化去扣减库存 , 可以一定程度上缓解数据库的并发压力 。 质量保障为了保证系统的稳定性 , 防止你的系统被秒杀 , 一些质量监控就不得不做 。
  1. 熔断限流降级 , 老生常谈 , 根据压测情况进行限流 , 可以使用sentinel或者hystrix 。 另外前端后端都该有降级开关 。
  2. 监控 , 该上的都上 , QPS监控、容器监控、CPU、缓存、IO监控等等 。
  3. 演练 , 大型秒杀事前演练少不了 , 不能冒冒失失的就上了吧 。
  4. 核对、预案 , 事后库存订单 金额、数量核对 , 是否发生超卖了?金额是否正常?都是必须的 。 预案可以在紧急情况下进行降级 。
数据统计活动做完了 , 数据该怎么统计?
  1. 前端埋点
  2. 数据大盘 , 通过后台服务的打点配合监控系统可以通过大盘直观的看到一些活动的监控和数据