秒杀的特点:时间极短、 瞬间用户量大。会带来的问题:
1.高并发
单机的Redis能承担3-4W的QPS,但是抢同一个商品的用户可能有几十万。缓存雪崩,缓存击穿,缓存穿透都是可能发生的。
2.超卖
秒杀的东西价格优惠,甚至赔本赚吆喝,超卖一定会出问题。
3.恶意请求
黄牛!搞个几十台机器搞点脚本,模拟出来十几万个人左右的请求。
4.链接暴露
网页的开发者模式就有ULR。写VUE的时候是事件触发然后去调用文件里面的接口看源码看不到,但是可以点击一下查看请求地址啊,不过可以对按钮在秒杀前置灰。
5.数据库
每秒上万甚至十几万的QPS(每秒请求数)直接打到数据库,基本上都要把库打挂掉,而且服务不单单是做秒杀的还涉及其他的业务,没做降级、限流、熔断啥的,别的一起挂,可能全站崩溃404。
对应的解决办法:
1.服务单一职责:现在设计都是微服务的设计思想,然后再用分布式的部署方式。
给秒杀开个服务,再建个数据库,设置索引。建完后记得用explain看看SQL的执行计划。
单一职责的好处就是就算秒杀没抗住,秒杀库崩了,服务挂了,也不会影响到其他的服务。(强行高可用)
2.秒杀链接加盐:URL动态化
链接要是提前暴露出去可能有人直接访问url就提前秒杀了,可以做个时间的校验链接,但请求地址比起页面人工点击的还是有很大优势,可以达到毫秒级别的。选择通过MD5之类的加密算法加密随机的字符串去做url,然后通过前端代码获取url后台校验才能通过。
3.Redis集群:
单机的Redis顶不住,秒杀本来就是读多写少,Redis集群,主从同步、读写分离,搞点哨兵,开启持久化直接无敌高可用!
4.Nginx:
Nginx是高性能的web服务器,并发也随便顶几万,但是我们的Tomcat只能顶几百的并发呀,负载均衡嘛,一台服务几百,那就多搞点,在秒杀的时候多租点流量机。
恶意请求拦截也需要用到它,一般单个用户请求次数太夸张,不像人为的请求在网关那一层就得拦截掉了,不然请求多了,服务器压力上去了,可能占用网络带宽或者把服务器打崩、缓存击穿等等。
5.资源静态化:
秒杀一般都是特定的商品还有页面模板,现在一般都是前后端分离的,所以页面一般都是不会经过后端的,但是前端也要自己的服务器啊,把能提前放入CDN服务器的东西都放进去,减少真正秒杀时候服务器的压力。
6.按钮控制:
秒杀前,一般按钮都是置灰的,只有时间到了,才能点击。需要前端的配合,定时去请求你的后端服务器,获取最新的北京时间,到时间点再给按钮可用状态。
7.限流:
前端限流:一般秒杀不会让你一直点的,一般都是点击一下或者两下然后几秒之后才可以继续点击,这也是保护服务器的一种手段。
后端限流:秒杀的时候肯定是涉及到后续的订单生成和支付等操作,一旦产品卖光了,return了一个false,前端直接秒杀结束,然后后端也关闭后续无效请求的介入了。
Tip:真正的限流还会有限流组件的加入例如:阿里的Sentinel、Hystrix等。
8.库存预热:非关系型数据库Redis
开始秒杀前你通过定时任务或者运维提前把商品的库存加载到Redis中去,让整个流程都在Redis里面去做,然后等秒杀结束了,再异步的去修改库存就好了。采用主从在高并发下可能超卖,用Lua 脚本功能解决。
9.限流&降级&熔断&隔离:
10.削峰填谷:MQ