秒杀系统优化方案
秒杀接口的简单流程
- 1.用户是否登陆,没有登陆返回失败
- 2.用户是否有收货地址
- 3.库存是否充足,没有库存返回失败
- 4.用户是否重复秒杀,秒杀过了返回
- 5.减库存,库存是否改变,没有改变返回失败
- 6.下订单,写入秒杀订单
- 7.秒杀成功进行支付
页面优化技术
- 1.页面缓存+ URL缓存+对象缓存
- 2.页面静态化,前后端分离
- 3.静态资源优化
- 4.CDN优化
页面缓存
如前端页面使用的是Thymeleaf这类模板引擎,可以直接在服务器渲染,然后把整个html页面当作string返回放入redis中进行缓存,把高并发的页面进行缓存(如秒杀商品列表,秒杀的商品信息),像这种页面的话缓存的时间不能设置太长,否则数据库修改后不能及时展示。
对象缓存
把需要用到的对象放到redis中进行缓存,如秒杀用户,秒杀的商品信息。
页面静态化
把静态页面放到静态资源里面,前端使用ajax来请求需要的数据。
多次访问页面的时候页面返回的状态会变为304,不在是200,并且会向服务端传入下图的参数,服务端收到这个参数后会检查这个接口的返回数据是否有发生改变,如果没有的话就会给客户端返回304,表示浏览器可以直接使用缓存的数据。
这个请求的方式还是会向服务端发生请求,如果不需要向服务器请求直接使用的话可以参考springboot的官方文档
- spring.resources 的相关配置
https://docs.spring.io/spring-boot/docs/2.1.13.BUILD-SNAPSHOT/reference/htmlsingle/
#static
spring.resources.add-mappings=true
spring.resources.cache-period= 3600
spring.resources.chain.cache=true
spring.resources.chain.enabled=true
spring.resources.chain.gzipped=true
spring.resources.chain.html-application-cache=true
spring.resources.static-locations=classpath:/static/
超卖问题的解决思路
- 1.数据库加唯一索引:防止用户重复购买(秒杀表里面把用户和商品ip作为唯一索引,在加上事物发生错误进行回滚)
- 2.SQL加库存数量判断:防止库存变成负数(在where 条件里面判断下库存是否>0,数据库本身在更新的时候会有锁,只能一个线程修改)
- 3.减少库存的时候update语句判断下返回值是否大于0,如果大于0说明修改数据库成功,才可以创建订单
秒杀接口优化
- 1.Redis预减库存减少数据库访问
- 2.内存标记减少Redis访问
- 3.请求先入队缓冲,异步下单,增强用户体验
对于高并发的访问解决数据库的瓶颈是最为重要的
思路:减少数据库访问
-
1.系统初始化,把商品库存数量加载到Redis
-
2.收到请求,Redis预减库存,库存不足,直接返回,否则进入3
-
3.请求入队,立即返回排队中
-
4.请求出队,生成订单,减少库存
-
5.客户端轮询,是否秒杀成功
具体实现方式
在项目中引入消息队列如RabbitMq,kafka等,在秒杀过程中分为两部分,消息入队前的操作和消息入队后的操作,入队前需要使用到的数据都从redis中取,入队后消费才正常的对数据库进行减库存,生成订单等操作。
项目初始化
- 把秒杀商品的库存放入redis中缓存,并把每件商品可以做一个标记是否秒杀完(可以使用Map进行标记)
- 秒杀接口具体实现
- 1.判断用户相关信息(是否登陆,是否填写收货地址等)
- 2.判断商品是否秒杀完(Map),秒杀完返回失败信息
- 3.预减库存可以使用redis的decr方法(原子操作),如果库存小于0标记一下该商品买完(Map标记),返回秒杀失败
- 4.判断商品是否重复秒杀(从redis中取相关信息)
- 5.把相关信息(用户信息以及商品id)发送到消息队列中,发送完就可以直接返回状态给给前端展示(排队中)
消费端消费信息
- 6.根据传来商品id从数据库中查找库存
- 7.大于0进行从数据库中进行减库存操作,小于0返回
- 8.判断减库存是否成功,成功的话生成订单并把秒杀成功信息放入redis中,失败的话把该商品秒杀完的信息存入redis中
前端页面处理
- 9.如果返回的是排队中的状态就轮询去查是否秒杀成功的接口
- 10.从秒杀订单表查找相关信息如果有订单的话就返回秒杀成功,如果没有订单信息的话有两种情况(1.消费端还没有消费,继续轮询,2.已经没库存了,可以从redis中取)
还可以使用nginx进行负载均衡配置
安全优化
- 1.秒杀接口地址隐藏
- 2.数学公式验证码
- 3.接口限流防刷
隐藏秒杀地址
思路:秒杀开始之前,先去请求接口获取秒杀地址
- 1.点击秒杀按钮的时候先去后端生成一个随机的字符串,存入redis,然后返回给前端,前端在根据这个字符串拼接成一个秒杀接口的后端路径,进行验证。
- 在点击秒杀按钮前可以用图形验证的方式来分散用户的请求,该方法对于减少并发量是十分有效的。
接口限流防刷
可以使用拦截器或者aop来实现减少对业务代码的侵入
使用注解的方式来设置时间,最大访问次数等
在需要控制的接口上面使用注解,获取接口路径的时候把用户、商品id、路径作为key,并设置初始次数。