欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

秒杀系统优化方案

程序员文章站 2022-06-20 08:37:08
...

秒杀接口的简单流程

  • 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,并设置初始次数。