基于SpringBoot+Reds+RabbitMQ实现的分布式秒杀系统
前端页面采用隐藏秒杀地址和使用随机秒杀地址来防止用户恶意刷接口,点击秒杀时会让用户输入数字计算验证码,输入正确后进入后端业务逻辑。
后端业务逻辑分为生产者和消费者。
生产者
- 生产者首先进行预加载,查询所有的商品列表,把每一个商品根据商品ID 和 库存容量 加入到redis 中,其次做一个内存标记,使用hashMap,将每一个商品id 都标记为 false。
- 使用令牌桶算法对其进行限流
- 判断刚刚随机生成的路径是否正确,然后在判断该商品是否已经卖出根据内存标记,如果都满足那么在redis中预减库存(因为初始化时,每一个商品Id和库存都存入redis中)
- 判断库存是否小于 0 ,如果不小于0说明减库存成功,
- 接着判断是否秒杀成功,从redis 中根据用户id 和商品id查询,如果存在说明该用户已经秒杀,不能重复秒杀
- 加入MQ,将用户id 和商品ID封装成对象序列化成JSON 字符串。
消费者
- 从队列中数据,将JSON字符串转换为对象,取出用户ID 和商品Id
- 从数据库中判断库存是否 <= 0,如果小于 0 说明库存为0直接返回。
- 从缓存中查看该订单是否秒杀到,如果秒杀到直接返回。没有秒杀到在缓存中写入该秒杀订单
- 执行秒杀事务,先判断减库存是否成功,如果成功写入秒杀订单。
在商品表中添加一个版本号字段,减库存业务时,通过商品id获取商品的版本号,在减库存操作时,先判断查询的verison 是否一致,一致则减库存成功。写入秒杀订单。
update set seckill_goods stock = stock - 1, version = version + 1
where id = #{goodsId} and stock > 0 and version = #{version}