一、前言

这篇文章的设计思想来源于沈剑。很受启发。为了加强记忆,做此笔记。

二、秒杀业务的典型场景

100w个人抢1w台小米

三、秒杀业务的特点

抢之前,需要读库存。如果还有库存,则写数据库进行锁库操作。考虑到人多货少。所以实际有100w人读了库存,但成功锁库的只有1w人。典型的读多,写少的场景。读是主要造成系统压力的操作。且这些读有两个特点:

  • 库存可以不精确,用户关心的是有货没货。并不一定关心到底还有多少货
  • 允许脏读。实际库存只有5台。但是展示给用户有10台都可以。因为用户最终下单锁库时,会去操作真正的库存。这个时候库存不足,可以直接给用户提示下单失败即可。因为即便下单之前读的库存精确,本来也不保证下单成功,因为人多机少

这两个特点,使得对于读库存的操作,可以使用缓存来扛

四、 秒杀业务的设计思路

一个典型的互联网系统架构设计如下:
1525355431208

  • 浏览器层 用户直接访问的入口是浏览器渲染的页面
  • 站点层 查询各种底层服务数据,拼装html页面,返回给浏览器
  • 服务层 屏蔽数据库访问细节,对站点层提供服务
  • 数据层 即数据库,比如mysql

4.1 对于读来说

既然读可以通过缓存来做,且允许一定的不精确。那么以上各级都可以做缓存。层层缓存,使得最终打到服务层的查询请求最少。

  • 浏览器层 通过浏览器缓存,减少用户频繁刷新造成的静态文件频繁加载。可考虑CDN缓存
  • 站点层 可将页面缓存,短时间内的重复访问,可以直接返回固定的缓存页面
  • 服务层 上面两部限制后,能到达这一层的读请求就减少了,对于这层的读请求,直接去缓存中读库存。不走数据库
  • 数据层 读请求走了上面的缓存,不允许读请求直接打到数据库

4.2 对于写来说

也就是下单

  • 浏览器层 通过js,限制用户点击下单的频率。点击后按钮置灰。
  • 站点层 限制同一账号下单请求次数,防止程序员用户绕过浏览器直接请求
  • 服务层 通过队列缓存住打下来的写请求,然后以数据库能接受的请求量,从队列中去除。打到数据库层,进行锁库操作
  • 数据层 直接下单改库存操作。由于上面几层的措施,保证了打到数据库的流量都是数据库能接受,不会被打垮。

4.3 架构核心思想如下图

1525356323976

  1. 写操作用队列限速
  2. 读操作走缓存
  3. 真实缓存异步更新到缓存

五、库存更新层面的技巧

采用乐观锁的方式修改库存
update xiaomi_phone set
quantity = quantity-#count#
where quantity >= #count#

六、解决恶意下单的用户

下单后,对用户订单设置一个支付时间约束。超时回退库存。

七、参考资料

https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651959391&idx=1&sn=fb28fd5e5f0895ddb167406d8a735548&scene=19#wechat_redirect