1、秒杀系统设计

秒杀业务最大特点就是高并发,考虑的不应该是秒杀业务应该如何进行,而是如何设计一个高并发系统,能承受大量峰值流量,下面着重考虑高并发下出现的问题以及解决方案。
1.1 服务单一职责(独立不是):
防止大量请求瞬间进来,把我们的系统压垮,秒杀业务应该满足服务单一职责(自己干自己的事,不影响其他服务)。
1.2 秒杀链接加密:
防止恶意攻击,模拟秒杀请求,1000次/s攻击;防止链接暴露,自己工作人员,提前秒杀商品。
1.3 库存预热+快速扣减:
如果走正常的加入购物车、占库存以及支付,整个流程就太慢了吗,在高并发系统中肯定会出现崩溃的问题,现在就可以进行预热的操作,比如,商品有400件,通过定时任务,扫描进redis中存一个400的信号量,想要秒杀的人进来后,先拿到信号量,无论是几百万的请求,只有400个人拿到请求,最终放行的就400个人,即使走正常的购物车逻辑,也不会有什么问题的
1.4 动静分离:
无论是秒杀服务还是其他服务都实现了动静分离,所有的静态请求直接由nginx给我们返回,如果是动态请求,才会路由到后台的网关,网关才会交给我们的服务。一个详情页有几十个请求(一个是动态请求),假如有10万个请求过来,算上静态请求就有几百万个请求。使用CDN网络,分担本集群压力。
cdn网络:使用阿里云,通过阿里云保存静态资源,阿里云会将静态资源放在各个服务节点(上海节点、北京节点、广东节点)访问静态资源时,阿里云会就近选择最快的节点,返回静态资源
1.5 恶意请求拦截:
恶意脚本,每秒刷1000次(访问商品详情页,或者秒杀链接),恶意请求的拦截一般在网关层,后台的请求都是正常的
1.6 流量错峰:
使用各种手段,将流量分担到更大的宽度时间点。比如输入验证码机制:防止是非人为的请求;输入验证码有快有慢,一秒的有10万人,两秒的有10万人,相当于把流量错开了,请求分散到各个时间点上了;加入购物车机制:选中商品,点击加入购物车,要结账,要锁库存还有其他操作,有快有慢
1.7 限流&熔断&降级
限流:前端限流:加入购物车每秒点击一次;后端限流:哪些是用户的正常行为,哪些是恶意行为,进行过滤,包括一过滤进来,即使是用户的正常行为,也进行限流(一秒点了10来次,只放行来一到两次),最终可以通过限流把大量的请求。比如100万请求,把不合理的请求去除点,还有60万请求,有些用户点了10次,放行一两次,去除其他请求,还剩6-10万请求一步一步操作,每到达一层,都做限流操作,把不合理的过滤掉,哪怕是合理的次数太多了,也给限制起来,最终给后台的流量就比较少了。可以限制次数,限制总量,举例:五台服务器部署了秒杀服务,峰值是10万每秒,在网关层进行总限流,发给秒杀服务的流量不能超过10万,超过10万了,就等上两秒,再把请求转过去。
熔断&降级:很重要,秒杀需要调用其他业务,A调用B服务,B服务调用C服务,B服务经常调用失败,给A调用B设置断路保护机制,知道调用B失败,下次就不在调用B服务了,否则一直在阻塞等待中,浪费资源。本来从A调用B服务,再到C服务,一般需要0.1秒,就可以释放占用的资源了,但是现在一直阻塞,3-5秒以后才释放,才告知请求失败,不合理。

流量太大了,可以将一部分请求转到降级页面,说当前服务太忙了,请稍后再访问
1.8 队列削峰
流量再大,哪怕有1000万,只要收的住请求,一收进来,就需要创建订单,并支付,一串逻辑,而且创建订单也很慢,还要扣库存,正常执行起来需要3-5秒时间,但是现在只要请求收到,并且是合法的,可以秒杀商品,现在有100个库存,放给后台100万个人,这100万个人都要秒杀,要争抢着100个库存,别去数据库争抢,在redis放了信号量,所以这100万个人去抢信号量,只要拿到信号量的人,放行给后台,后台将请求发送给一个队列,我们的订单服务就去监听这个秒杀队列,只要秒杀的请求能被放进队列中,那订单服务就在后台慢慢的创建订单,创建个5-10秒都是可以的(转到页面提示抢购成功,5秒以后支付订单)。
如果是单体秒杀,无所谓。一个商品苹果手机,100件商品,能获取1信号量后,能放进来的请求就是100个,走正常的下订单支付流程都是可以的。但是现在假设处在淘宝的双十一现场,凌晨12点,淘宝全网的商品,可能有几百万之多,每个商品假设都有100个的库存,大量请求过来秒杀,一个商品100个请求,全部就是几亿个请求获取到信号量进入到后台,这个时候,队列的作用就特别明显了。所有请求一进来,秒杀成功(抢到货了),就把这个请求放到队列里面,整个后台的订单集群就来监听这个队列,队列做好集群化(几万亿的数据都没有问题),后台订单集群慢慢按照自己的能力来进行消费,无论怎么消费,一分钟以后都可以返回结果了,订单可能出现延迟,但最终都会支付成功
秒杀具有瞬间高并发的特点,限流+异步+缓存(页面静态化)+独立部署。
独立部署:瞬间高流量会导致其他服务不可访问。
2、Springboot整合定时任务与异步任务
2.1、定时任务
1、@EnableScheduling 开启定时任务
2、@Scheduled 开启一个定时任务
3、自动配置类 TaskSchedulingAutoConfiguration
2.2、异步任务
1、@EnableAsync 开启异步任务
2、@Async 给希望异步执行的方法上标注
3、自动配置类 TaskExecutionAutoConfiguration
通过ThreadPoolTaskExecutor创建一个线程池,而ThreadPoolTaskExecutor最终实现的是Executor
2.3、注意事项
1、Spring中的6位组成,不允许第七位的年
2、在周几的位置,1-7代表周一到周日;mon-sun
3、定时任务超长,不应该阻塞。但是默认是阻塞的(如何解决)
3.1、可以让业务运行以异步的方式,自己提交到线程池
3.2、支持定时任务线程池:设置TaskSchedulingProperties
spring.task.scheduling.pool.size=5
3.3、让定时任务异步执行
解决方案:定时任务+异步任务来完成定时任务不阻塞的问题
3、秒杀前准备
4、幂等性保证

