一、简介
秒杀系统就是电商系统的一种形式,通过设计秒杀模块来应对实际电商平台中最考验系统架构的部分。
秒杀系统特点:业务简单(卖家查询,买家下订单减库存),瞬时并发量高。
二、设计思路
核心思路是通过缓存,异步,限流来保证系统的高并发和高可用。
设计思路:
将请求拦截在系统上游,降低下游压力
充分利用缓存:利用缓存可极大提高系统读写速度
消息队列:消息队列可以削峰,将拦截大量并发请求,这也是一个异步处理过程,后台业务根据自己的处理能力,从消息队列中主动拉取请求信息进行业务处理。
三、SpringBoot版的简单实现
使用环境 jdk 8 、SpringBoot 2.7.3、 MySQL8.3、Redis 、RabbitMQ
工具 idea2022.2 、sqLyog、 Apifox+Jmeter
3.1、数据库的搭建
库存表
订单表
3.2 SpringBoot文件创建
pom 文件编写
使用redis和mq和fastjson2和swagger-annotations(使用R统一返回值类型)
** 项目架构**
common 公共类
调用了ok和error来返回成功或失败
调用message code data
config配置类
RedisConfig
将redis序列化排列使得传出的对象简洁明了
RedissionConfig
配置一个redis的分布式锁
Redis 实现分布式锁主要步骤
指定一个 key 作为锁标记,存入 Redis 中,指定一个 唯一的用户标识 作为 value。
当 key 不存在时才能设置值,确保同一时间只有一个客户端进程获得锁,满足 互斥性 特性。
设置一个过期时间,防止因系统异常导致没能删除这个 key,满足 防死锁 特性。
当处理完业务之后需要清除这个 key 来释放锁,清除 key 时需要校验 value 值,需要满足 只有加锁的人才能释放锁 。
RabbitConfig
RabbitMQ的配置类
application.yml配置
实体类
orders 类,Inventory同理
mapper数据持久层
orderMapper
提交订单的方法
InventoryMapper
修改库存方法 ,查询库存方法 ,查表内库存信息方法
映射文件
service数据服务层
业务层接口
order提交订单业务
开机更新数据库库存到redis库业务
实现类
库存启动更新到redis的操作
订单实现类
redisson是调用生成锁的方法 rabbitTemplate使用Mq传递消息
订单操作流程如下
controller传入Orders对象
impl接受到值order
生成一个分布式锁,判断锁是否超时
调用redis库中的库存 根据我们之前传入的key值查询
判断redis库存值是否满足订单的需求,若满足执行 让inventory.set一个新的库存值。redis库存不足订单需求时,就要停止卖了。
拿到新的值后向redis库中传入新的值 依旧根据 key :value 的方式
这时我们redis的库已经修改了,给用户返回的信息显示的就是已经购买到了。此时使用mq来作为一个传信员传递信息给数据库让他修改库存。因为redis的响应速度大于mysql,当redis缓存成功时。我们让mq发一个消息让数据库慢慢地修改库存就行了。
这时这条消息会传到指定队列上我们写一个实现类来操作这条信息
这样数据库才真的修改了。逻辑的最后要关闭锁,把锁交给下一个线程使用。
controller数据控制层
controller层是用来接受前台数据和返回页面请求信息的,所有我们定义的请求方式和传参类型,前后端要保持一致。
启动测试
数据库存250
redis库存启动传入
压力测试发送请求 一个线程就是一个http请求 我们使用jmeter发送1000个
前边的线程可以买到
依次出现抢到抢不到的现象
到最后真的没有了
数据库和redis也没有成负值,没有超卖
总结
这是我个人的思路总结,有很多方面其实都没有那么完美,只是对高并发的一个模拟实现。期待大家的指正。