如何设计秒杀系统?


如何设计秒杀系统?
本文是敖丙大佬的文章的总结精炼。(原文:阿里面试官问我:如何设计秒杀系统?我的回答让他比起大拇指)

场景

10万人秒杀100件商品

问题

1.高并发

时间极短、瞬间用户量大,可能会导致缓存雪崩、缓存击穿、缓存穿透

2.超卖

只卖100个,不能多卖

3.恶意请求

如黄牛用几十台机器搞点脚本,模拟大量请求。

4.链接暴露

如直接从浏览器看网页源码,或者开发人员自身知道秒杀链接,秒杀时提前请求

5.数据库:

每秒上万甚至十几万的QPS(每秒请求数)直接打到数据库,基本上都要把库打挂掉,而且服务可能不单单是做秒杀,还涉及其他的业务,没做降级、限流、熔断啥的,会导致其他业务一起挂,小公司的话可能全站崩溃404

解决办法:

1.服务单一职责

现在设计都是微服务的设计思想,然后再用分布式的部署方式,给秒杀单独开个服务,把秒杀的代码业务逻辑放在一起,单独建立一个数据库,即秒杀库。
好处是就算秒杀没抗住,秒杀库崩了,服务挂了,也不会影响到其他服务。

2.秒杀连接加盐

把URL动态化,就连写代码的人都不知道,比如通过MD5之类的加密算法加密随机的字符串去最url同伙前端代码获取URL后台校验才能通过。
好处是防止链接提前暴露而导致有人直接访问url就提前秒杀,或脚本秒杀(比人工点击快)

3.Redis集群

单机的Redis顶不住,秒杀时读多写少,可以Redis集群,主从同步、读写分离,还可以搞点哨兵,开启持久化
在这里插入图片描述

4.Nginx负载均衡

Nginx是高性能的web服务器,可以顶几万并发,Tomcat只能顶几百的并发,用Nginx给Tomcat做负载均衡,可以在秒杀时多租点流量机。好处是这样可以提升集群的能力
在这里插入图片描述
恶意请求拦截也需要,一般单个用户请求次数太夸张,不想人为的请求在网关那一层就得拦截,防止恶意抢,更防止这种恶意把服务器压力提上去,可能占用网络带宽或者把服务器打崩、缓存击穿等

5.资源静态化

秒杀一般都是特定的商品和页面模板,现在一般都是前后端分离的,所以页面一般都是不会经过后端,但是前端也要自己的服务器,把能提前放入cdn服务器的东西都放进去,反正把所有能提升效率的步骤都做一下,减少真正秒杀时候服务器的压力。

6.按钮控制

没到秒杀前,一般按钮都是置灰的,只有时间到了,才能点击。这是因为怕在时间快到的最后几秒秒疯狂请求服务器,还没到秒杀的时候基本上服务器就挂了。
这需要前端的配合,定时去请求后端服务器,获取最新的北京时间,到时间点再给按钮可用状态。按钮可以电机之后置灰几秒,以免在开始之后一直点。

7.限流:可以分为前端限流和后端限流。

前端限流:前端设置点击一下或两下后隔几秒才可以继续电机,这也是保护服务器的一种手段。
后断限流:一旦100个产品卖光了,return一个false,前端直接秒杀结束,然后后端也关闭无效请求的介入。(真正的限流还会有限流组件的加入例如:阿里的Sentinel、Hystrix等)

8.库存预热:

秒杀的本质就是对库存的抢夺,不要每个秒杀的用户来都去数据库查询库存校验库存,然后扣减库存,撇开性能因数,这样很繁琐繁琐,且对业务开发人员不友好,而且数据库顶不住。

非关系型的数据库Redis能顶。要开始秒杀前通过定时任务或者运维同学提前把商品的库存加载到Redis中去,让整个流程都在Redis里面去做,等秒杀介绍,再异步的去修改库存。
但是用了Redis就有一个问题,上面说了采用主从,就是会去读取库存然后再判断然后有库存才去减库存,正常情况没问题,但是高并发的情况问题就很大。

比如现在库存只剩下1了,对于高并发,4个服务器一起查询了发现都是还有1个,那大家都觉得是自己抢到了,就都去扣库存,那结果就变成了-3,是的只有一个是真的抢到了,别的都是超卖的。咋办?——Lua脚本

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

Lua脚本是类似Redis事务,有一定的原子性,不会被其他命令插队,可以完成一些Redis事务性的操作。这点是关键。

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

9.限流&降级&熔断&隔离

这个为啥要做呢,不怕一万就怕万一,万一你真的顶不住了,限流,顶不住就挡一部分出去但是不能说不行,降级,降级了还是被打挂了,熔断,至少不要影响别的系统,隔离,你本身就独立的,但是你会调用其他的系统嘛,你快不行了你别拖累兄弟们啊。

10.削峰填谷:

说到这个名词,就是 MQ,你买东西少了你直接100个请求改库可能没问题,但是万一秒杀一万个,10万个呢?服务器挂了,程序员又要背锅的。

Tip:可能小伙伴说我们业务达不到这个量级,没必要。但是我想说我们写代码,就不应该写出有逻辑漏洞的代码,至少以后公司体量上去了,别人一看居然不用改代码,一看代码作者是敖丙?有点东西!

可以把它放消息队列,然后一点点消费去改库存就好了,不过单个商品其实一次修改就够了,这里说的是某个点多个商品一起秒杀的场景,像极了双十一零点。
在这里插入图片描述