本系统是使用SpringBoot开发的高并发限时秒杀系统,实现基本的登录、查看商品列表、秒杀、下单等功能。并且针对高并发情况作了页面级、服务级和安全级的优化,提升系统的并发度。
-
将请求尽量拦截在系统上游
-
充分利用Redis缓存
将用户输入的密码和固定Salt通过MD5加密生成第一次加密后的密码,再将该密码和随机生成的Salt通过MD5进行第二次加密,将第二次加密后的密码和生成的随机Salt存数据库
好处:
- 第一次作用:防止用户明文密码在网络进行传输
- 第二次作用:防止数据库被盗,避免通过彩虹表反推出密码
验证用户账号密码都正确情况下,通过UUID生成唯一id作为token,再将token作为key、用户信息作为value模拟session存储到redis,同时将token存储到cookie,保存登录状态
优点: 在分布式集群情况下,服务器间需要同步,定时同步各个服务器的session信息,会因为延迟到导致session不一致,使用redis把session数据集中存储起来,解决session不一致问题。
使用JSR303和自定义校验器[@Constraint用validatedBy自定义校验规则],实现对用户手机、密码的验证,使得验证逻辑从业务代码中脱离出来。
使用@ControllerAdvice对Controller层进行“切面”环绕,使用@ExceptionHandler进行具体的业务的织入来,实现自定义异常拦截器,拦截所有异常,并对各种异常进行相应的处理,有利于对异常进行统一维护管理。
- 页面缓存:通过ThymeleafViewResolver手动渲染详情页面并缓存到redis,减少服务端请求连接数。
- 对象缓存:包括对用户信息、商品信息、订单信息和token等数据进行缓存,利用缓存来减少对数据库的访问,加快查询速度。
对商品详情页和订单详情页进行静态化处理,并写入redis缓存,动态数据通过Ajax请求从服务端获取,实现前后端分离,打开速度有明显提高
描述:通过三级缓冲保护,1、本地标记 2、redis预处理 3、RabbitMQ异步下单,最后才会访问数据库,大力度减少对数据库的访问。
实现:
- 在秒杀阶段使用本地标记对用户秒杀过的商品做标记,若被标记过直接返回重复秒杀,未被标记才查询redis,通过本地标记来减少对redis的访问
- 抢购开始前,将商品和库存数据同步到redis中,所有的抢购操作都在redis中进行处理,通过Redis预减少库存减少数据库访问
- 为了保护系统不受高流量的冲击而导致系统崩溃的问题,使用RabbitMQ用异步队列处理下单,做缓冲保护。
- 客户端js轮询接口,获取处理状态
- 对库存更新时,先对库存判断,只有当库存大于0才能更新库存
- 对用户id和商品id建立一个唯一索引,通过这种约束避免同一用户发同时两个请求秒杀到两件相同商品
- 数据库乐观锁,给商品信息表增加一个version字段,为每一条数据加上版本。每次更新的时候version+1,并且更新时候带上版本号,当提交前版本号等于更新前版本号,说明此时没有被其他线程影响到,正常更新,如果冲突了则不会进行提交更新。当库存是足够的情况下发生乐观锁冲突就进行一定次数的重试。
描述:秒杀开始时,输入正确的验证码后,用户点击秒杀按钮,系统会请求生成秒杀地址的接口,生成用户商品认证信息[MD5(salt+userId+goodsId)],接口判断认证后才会返回真正的秒杀地址,[userId+goodsId]保证了每个用户的秒杀地址是唯一的。
优点:
- 秒杀地址隐藏防止恶意的机器人和爬虫刷单
- 图形验证码分散用户的请求
实现:
秒杀地址隐藏
-
点击秒杀按钮,服务端接口收到传参[goodsId, userId]同时使用MD5加salt对其进行加密,生成一个随机数[用户商品验证信息],写入redis缓存,并返回给前端
-
前端使用该随机数拼上真正的秒杀url,去请求秒杀接口
-
后端接口收到请求,先从缓存中取出随机数缓存,验证正确后,才能进入秒杀逻辑,否则返回失败信息
图形验证码
-
前端通过把商品id作为参数调用服务端创建验证码接口
-
服务端根据前端传过来的商品id和用户id生成验证码,并将商品id+用户id作为key,生成的验证码作为value存入redis,同时将生成的验证码输入图片写入imageIO让前端展示
-
将用户输入的验证码与根据商品id+用户id从redis查询到的验证码对比,相同就返回验证成功,进入秒杀;不同或从redis查询的验证码为空都返回验证失败,刷新验证码重试
自定义类实现HandlerInterceptor接口在preHandler方法中实现限制规则,限制用户在规定的时间内最多点击maxCount次秒杀按钮,使用限流来进行限制访问量,当达到限流阀值maxCount时,后续请求会被降级;降级后的处理方案可以是:返回排队页面(高峰期访问太频繁,等一会重试)。