设计秒杀系统的一些思路

 

设计一个秒杀系统可以很难也可以很容易。下面介绍两种思路

 

一、随机抽取(简单粗暴)

  • 第一步:用户点击秒杀后,直接在前端随机丢弃一些请求,返回给抢单失败,另外请求一些进入后端系统。
  • 第二步:提前部署redis集群,存储参与用户的ID,这样redis只有存的压力。
  • 第三步:然后同步记录去重, 再随机抽100个参与用户。(从秒杀开始后一定时间段内提交请求的用户中抽取)

其实也是公平的 而且应该比“凭手速”更公平 因为如果完全按到达服务器的时间算 有太多用户不可控但短期内不改变的因素会影响成功率 比如网速 设备性能

 

二、经典设计

总体思路:尽量将请求拦截在系统上游;读多写少的场景多使用缓存。 

 

 

秒杀系统的普遍问题:

  1. 高并发
  2. 超卖
  3. 恶意请求
  4. 链接暴露
  5. 数据库

 

一般解决思路:

前端层:

    前段限流:按钮置灰,活动开始前,前端定时检测当前时间,到点了就取消置灰;js限制用户几秒之内只能点击一次

网络层:

   cdn预热:一些秒杀相关的静态文件可以先推到cdn

   nginx:负载均很,临时加很多台秒杀服务器;拦截恶意请求(请求次数太夸张,对单个ip每秒访问次数加限制、加黑名单)

   网络宽带:临时提高宽带(云服务器)

后端层:

    设计系统,总体把握一个单一原则,秒杀系统不影响其他系统的正常运行。

缓存层:   

      redis部署:集群、主从同步、读写分离、哨兵,开启持久化(单一职责)

      redis预热:先把库存商品加载到redis,结束后再异步修改数据库

业务层:

      高并发:服务设计单一职责,单独设计一个秒杀服务,有助于扩容。(单一职责)

      链接暴露:秒杀链接加盐,MD5之类的加密算法加密随机的字符串去做url,然后通过前端代码获取url后台校验才能通过。

      服务降级:用户抢到即为成功,订单具体处理异步去操作。

      削峰填谷:MQ(设置定长队列能强制避免超卖)。

持久层:

      数据库:为了防止秒杀打挂数据库影响其他业务,单独设计一个秒杀表。(单一职责)

 

 

 

 一些补充:

在争抢库存是,会利用到redis-Lua:

Lua 脚本功能是 Reids在 2.6 版本的最大亮点, 通过内嵌对 Lua 环境的支持, Redis 解决了长久以来不能高效地处理 CAS (check-and-set)命令的缺点, 并且可以通过组合使用多个命令, 轻松实现以前很难实现或者不能高效实现的模式。

使用Lua脚本的好处:

  • 减少网络开销。可以将多个请求通过脚本的形式一次发送,减少网络时延。
  • 原子操作。redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。因此在编写脚本的过程中无需担心会出现竞态条件,无需使用事务。这个很关键
  • 复用。客户端发送的脚本会永久存在redis中,这样,其他客户端可以复用这一脚本而不需要使用代码完成相同的逻辑。

 写一个脚本把判断库存扣减库存的操作都写在一个脚本丢给Redis去做,那到0了后面的都Return False了是吧,一个失败了你修改一个开关,直接挡住所有的请求,然后再做后面的事情。

 

 

 

 

 

 

posted @ 2020-02-08 20:34  得记点什么了  阅读(1016)  评论(0编辑  收藏  举报