秒杀设计逻辑

秒杀

一、特点

1、时间短

2、瞬间请求的量非常大

二、需求注意的点

1、不能超卖

2、防黑产、黄牛;机器的请求速度比人的手速快太多了。

3、舜间爆发的高流量

  • 典型的读多写少的场景(Cache缓存)
  • 页面静态化,利用CDN服务器缓存前端文件
  • 按钮置灰3秒(利用风控规则过滤非法用户)
  • 接口层可以做开关限流(一旦抢购结束,则直接返回失败)
  • 堆机器,搭建集群,利用Nginx做负载均衡
  • 热点隔离,增加资源,有限放流(熔断)多次请求合并为一次

4、尽量把请求拦截在上层。Mysql

Mysql单机读能力为5k,写能力为3k

redis单机读能力最高可达10w,写能力达到3~5w

5、预热。运营人员提前将数据写入redis

6、异步去扣减库存。(消息队列)

三、秒杀架构原则

1、尽量将请求拦截在系统上游,到数据库的请求应该是越来越少,应该是一个漏斗型。


我的总结

1、准备工作

  • 隔离,和正常业务分开,以免影响正常业务。
  • 风控,防机器人刷单。记录所有请求,1秒钟多次请求可以判断为机器人;专业防控安全软件;刚注册没买过东西的,提示没中。一个账号只允许接受1个请求,其他请求过滤。
  • 秒杀前按钮置灰
  • 缓存预热

2、前端页面

CND缓存前端静态页面

3、Nginx

负载均衡

如用户是否具有秒杀资格、商品状态是否正常、秒杀是否已经结束等;过滤大量无效请求。

4、业务逻辑

  • 业务无状态可以扩展
  • 限流
  • 接口做开关,结束后,关闭开关,直接返回秒杀结束。或按时间自动关开头。
  • redis分布式锁,lua脚本保证原子性减预减库存;
  • 队列。订单异步MQ入队列。付款后库存队列。

5、数据库

  • 从MQ读消息入库,异步减库存和记录日志。减小数据库压力。

  • 水平分库,物理上进行分流。

  • 库存字段设置INT UNSIGNED,不允许出现负值。

置灰实现方案

使用JavaScript脚本控制,在秒杀商品静态页面中加入一个JavaScript文件引用,该JavaScript文件中包含秒杀开始标志为否;当秒杀开始的时候生成一个新的JavaScript文件(文件名保持不变,只是内容不一样),更新秒杀开始标志为是,加入下单页面的URL及随机数参数(这个随机数只会产生一个,即所有人看到的URL都是同一个,服务器端可以用redis这种分布式缓存服务器来保存随机数),并被用户浏览器加载,控制秒杀商品页面的展示。这个JavaScript文件的加载可以加上随机版本号(例如xx.js?v=32353823),这样就不会被浏览器、CDN和反向代理服务器缓存

这个JavaScript文件非常小,即使每次浏览器刷新都访问JavaScript文件服务器也不会对服务器集群和网络带宽造成太大压力。

如何只允许第一个提交的订单被发送到订单子系统

由于最终能够成功秒杀到商品的用户只有一个,因此需要在用户提交订单时,检查是否已经有订单提交。如果已经有订单提交成功,则需要更新 JavaScript文件,更新秒杀开始标志为否,购买按钮变灰。事实上,由于最终能够成功提交订单的用户只有一个,为了减轻下单页面服务器的负载压力,可以控制进入下单页面的入口,只有少数用户能进入下单页面,其他用户直接进入秒杀结束页面

前端层的请求拦截,只能拦住小白用户(不过这是99%的用户哟),高端的程序员根本不吃这一套,写个for循环,直接调用你后端的http请求,怎么整?

(1)同一个uid,限制访问频度,做页面缓存,x秒内到达站点层的请求,均返回同一页面

(2)同一个item的查询,例如手机车次,做页面缓存,x秒内到达站点层的请求,均返回同一页面

站点层的请求拦截,只能拦住普通程序员,高级黑客,假设他控制了10w台肉鸡(并且假设买票不需要实名认证),这下uid的限制不行了吧?怎么整?

(1)大哥,我是服务层,我清楚的知道小米只有1万部手机,我清楚的知道一列火车只有2000张车票,我透10w个请求去数据库有什么意义呢?对于写请求,做请求队列,每次只透过有限的写请求去数据层,如果均成功再放下一批,如果库存不够则队列里的写请求全部返回“已售完”

(2)对于读请求,还用说么?cache来抗,不管是memcached还是redis,单机抗个每秒10w应该都是没什么问题的;

你可能感兴趣的:(面试,秒杀,缓存)