SpringBoot商城秒杀系统-04-项目总结

秒杀项目源码

面试过程对项目的概述:

整个业务流程可以分为收单和下单两个阶段,两个阶段以下单这个操作为界限,分别概括如下:
在这里插入图片描述

收单流程(用户侧)

  • 秒杀之前对秒杀商品进行缓存预热
  • 访问秒杀入口之前,首先判断用户状态是否正确(用户是否登录–shiro实现)
  • 访问秒杀接口之前,再秒杀商品状态是否正确(秒杀未开始/秒杀进行中/秒杀结束),只有秒杀进行中秒杀按钮才可用,避免无效请求–js实现
  • 访问秒杀入口之前进行验证码校验,过滤掉机器人。生成IP黑名单进行ip校验(机器学习的方法),过滤掉黄牛的大量请求。
  • 等这些状态全部校验通过,将下单请求发送至Redis进行预扣库存,扣库存成功则将秒杀信息入队,同时返回给用户正在排队中。
  • 对校验失败和库存已经为零时则直接返回秒杀失败。实现上层限流。
收单流程存在的问题:
  • 页面静态化
    对商品详情和订单详情进行页面静态化处理,页面是纯html,动态数据是通过接口从服务端获取,实现前后端分离,静态页面无需连接数据库打开速度较动态页面会有明显提高。
  • 秒杀的倒计时功能时怎么样实现的
    首次访问秒杀页面的时候获取秒杀的开始和结束时间以及服务端的当前时间,在客户端进行倒计最后提交订单时再次校验服务端与客户端的时间。
  • 如何防止短时间内的大量请求–使用限流器
    guava的RateLimiter使用的是令牌桶算法,也就是以固定的频率向桶中放入令牌,例如一秒钟10枚令牌,实际业务在每次响应请求之前都从桶中获取令牌,只有取到令牌的请求才会被成功响应,
  • 几千万个请求同时对Redis进行修改,怎么保证修改正确?
      分布式锁+失效时间
    用SETNX实现分布式锁,操作库存都进行加锁和解锁操作保证安全。失效时间的设置保证了发生异常时不会死锁。使用setnx加锁的时候使用UUID作为value,当加锁成功时对库存进行操作并发回给客户端uuid作为解锁的唯一标识。分布式锁demo
      消息队列
    在并发量过大的情况下,可以通过消息中间件进行处理,把并行读写进行串行化。把Redis.set操作放在队列中使其串行化,必须的一个一个执行。

下单流程

  • 所有的订单请求都是在MQ中的,拿到秒杀请求后首先判断用户是否下单成功过避免重复秒杀,同时查库存是否充足,库存不足则直接返回秒杀失败。
  • 然后执行真正的减库存和生成订单的操作(在一个事务中执行),减库存的时候采用悲观锁:select * from stock where product_id=xxx for update,for update 就已经上锁,update stock set count=count-1 where product_id=xxx and count>0;
  • 下单成功后返回给用户下单成功并提醒其及时支付。
  • 用户一段时间(如:30mins)没有支付,则订单作废,库存恢复,给其他排队中的用户提供购买机会
下单流程中可能的问题
  • 如何避免超卖:悲观锁结合事务的使用避免了超卖的发生,当库存为0的时候减库存失败事务会进行回滚。
  • 如何判断用户是否重复秒杀,查询订单库当前用户是否已经生成过订单。同时将订单库的用户ID和商品ID设置为唯一索引,当有两条相同订单插入的时候就会失败回滚。
  • 秒杀业务挂了怎么样不影响其他业务?服务熔断

项目的亮点:

  • 使用分布式Seesion,可以实现让多台服务器同时可以响应。
  • 使用redis做缓存提高访问速度和并发量,减少数据库压力,利用内存标记减少redis的访问。
  • 使用消息队列完成异步下单,提升用户体验,削峰和降流。
  • 安全性优化:shiro安全框架,数学公式验证码,接口限流防刷。
  • 页面缓存,加快用户访问速度

开发技术

前端技术 :Bootstrap + jQuery + Thymeleaf

后端技术 :SpringBoot 2.0+ MyBatis + MySQL

中间件技术 : Druid + Redis + RabbitMQ

关键开发过程记录

Shiro安全框架做登录认证

原项目中使用了两次MD5手动加密进行登录管理,显然更加麻烦,在此使用shiro安全框架进行了优化。

Session共享

既然使用了shiro,那么必不可能再去像源码那样去共享session,太复杂!使用shiro-redis插件完成session共享

RabbitMQ异步下单

  • 系统初始化,把商品库存数量stock加载到Redis上面来。
  • 后端收到秒杀请求,Redis预减库存,如果库存已经到达临界值的时候,就不需要继续请求下去,直接返回失败,即后面的大量请求无需给系统带来压力。 缓存这个秒杀用户的信唯一息,避免一个账户秒杀多个商品,判断是否重复秒杀。
  • 库存充足,且无重复秒杀,将秒杀请求封装后消息入队,同时给前端返回一个code (0),即代表返回排队中。(返回的并不是失败或者成功,此时还不能判断)
  • 前端接收到数据后,显示排队中,并根据商品id轮询请求服务器(考虑200ms轮询一次)。
  • 后端RabbitMQ监听秒杀通道,如果有消息过来,获取到传入的信息,执行真正的秒杀之前,要判断数据库的库存(避免超卖),然后执行秒杀事务(秒杀事务是一个原子操作:库存减1,下订单,写入秒杀订单)。
  • 此时,前端根据商品id轮询秒杀结果,查看是否生成了商品订单,如果请求返回-1代表秒杀失败,返回0代表排队中,返回>0代表商品id说明秒杀成功。

图形验证码

为防止机器人,刷票软件恶意频繁点击按钮来刷请求秒杀地址接口。在点击秒杀之前,先输入验证码,分散用户的请求,只有当验证码正确之后才会获得秒杀地址。

接口限流防刷

思路:利用缓存实现,用户每次点击之后访问接口的时候,在缓存中生成一个计数器,第一次将这个计数器置1后存入缓存,并给其设定有效期,比如一分钟,一分钟之内再访问,那么数值加一。一分钟之内访问次数超过限定数值,直接返回失败重新登录。下一个一分钟,数据重新从0开始计算。因为缓存具有一个有效期,一分钟之后自动失效。

页面缓存

将页面以html的形式存入redis,当用户刷新页面时直接从reids中取html代码,减少用户对数据库的访问。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值