可能会遇到的问题
高并发
超卖
链接暴露
高可用
解决办法
限流:在秒杀开始之前,秒杀按钮置灰。
解决超卖:
不同用户在读请求的时候,发现商品库存足够,然后同时发起请求,进行秒杀操作,减库存,导致库存减为负数。
最简单的方法,更新数据库减库存的时候,进行库存限制条件,当库存足够时才进行操作。
Redis预减库存
系统初始化,把商品库存数量加载到Redis,收到秒杀请求后,Redis预减库存,如果库存已经到达临界值的时候,后续请求直接返回失败。
会遇到问题:先在 redis 中减库存,再判断订单。重复请求会导致 redis减库存成功,而下单失败,最终的结果会是商品还有库存,而 redis中却没有库存。 (将生成订单的逻辑放在预减库存之前)
Redis分布式锁
lua脚本来进行原子操作来实现
RabbitMQ
库存充足,将秒杀请求封装后消息入队,同时给前端返回一个code (0),即代表返回排队中。前端接收到数据后,显示排队中,并根据商品id轮询请求服务器(考虑200ms轮询一次)。后端RabbitMQ监听秒杀消息,如果有消息过来,获取到传入的信息,执行真正的秒杀之前,要判断数据库的库存,判断是否重复秒杀,然后执行秒杀事务(秒杀事务是一个原子操作:库存减1,下订单,写入秒杀订单)。此时,前端根据商品id轮询请求接口,查看是否生成了商品订单。
页面缓存+URL缓存+对象缓存
将页面直接缓存到用户的浏览器上面。(添加失效时间)
页面缓存:未作页面静态化:请求某一个页面,访问缓存,查看缓存中是否有,有则直接返回,没有的话,将数据渲染到html页面再存到缓存,再将整个html页面返回给客户端显示。
URL缓存:和页面缓存类似,只不过针对不同页面。
对象缓存:更新数据库与缓存,先更新数据库后删除缓存,再将对应信息一起再写回缓存里面。
页面静态化
第一次是请求后台要渲染好的html页面,之后的请求都是直接访问用户本地浏览器的缓存的html页面 ,静态资源,然后前端通过Ajax来访问后端,只去获取页面需要显示的数据返回即可。
安全优化
秒杀接口地址隐藏
每次点击秒杀按钮,通过用户id和商品id生成字符串(对字符串进行加密),动态拼接而成的地址。
对秒杀接口进行限流
设置验证码、令牌桶算法(设置最多点击次数)
通过自定义注解来减少重复的代码
其他功能
登录功能 :密码加密(MD5加密)
使用分布式Session,直接用redis存储,或者直接将用户信息存储在redis中(序列化后存入redis)。
优化登录功能:不需要每一个页面都判断用户是否存在(在接收User之前就对他进行校验)。自定义参数解析器类,实现HandlerMethodArgumentResolver 接口,并实现其方法,通过@Configuration注册到Spring boot
依赖
thymeleaf
mybatis-plus
lombok
其他
hikari连接池
@Controlleradvice:控制器抛出的异常
@ExceptionHandle:
其他方案
预约给Token,有token的才能秒杀
网关限流:重复的ip