stayingnumber1 / miaosha

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

高并发秒杀系统优化

一. 项目开发背景
  1. 基于SpringBoot框架在传统的秒杀项目上面进行支持高并发的优化.做压测进行先后对比.在单台和集群部署下的系统的QPS值的对比.
  2. 除了基本的手机+密码登录,查看商品,商品详情页面,立即秒杀,秒杀详情订单信息.
  3. 对Redis/RabbitMQ有更加深入的学习.理解高并发的项目解决方案实现过程.
  4. 秒杀流程是:订单详情点击商品,判断库存,判断是否秒杀到,减库存,下订单,写入秒杀订单里面.
  5. redis通用key的封装,使用模板设计模式.

二. 项目使用技术
  1. 前台技术
    Html,JavaScript,CSS,Jquery,Bootstrap,layui.

  1. 后台技术
    SpringBoot 1.5.8,MyBatis,Thymeleaf模板引擎2.0(3.0没有那个SpringWebContext),Druid数据库连接池.

  1. 数据库
    MySQL5.7

  1. 缓存技术
    Redis的高可用部署方式.Redis的Session管理.集群.持久化.

  1. 消息队列
    RabbitMQ的基于交换机的Direct模式.

  1. 项目部署
    Docker部署/基于打成jar的部署.Tomcat集群部署,做负载均衡.

  1. 压测工具
    JMeter,1000个线程循环10次.10000次请求,聚合报告的方式.查看系统QPS.

  1. 代码优化
    使用Lombok来优化set/get方法,减少项目的臃肿.

  1. 项目性能监控
    后面差分为微服务的架构,使用SpringAdmin进行监控项目.

三. 项目要点技术整理
  1. 使用两次MD5加密
    用户输入的密码和固定的Salt通过MD5加密生成第一次加密后的密码,Ajax异步提交到后台控制器.这个时候 要使用固定的盐加密一次,就是输入密码到表单密码.这里需要将这个固定的盐值保存是秒杀用户表里面.接下来 就是将表单密码和一个秒杀用户的随机颜值在加密一次后将该密码保存至数据库里面. 好处:防止明文密码在网络传输不安全.其次是防止数据库被盗后,密码MD5反查彩虹表得到密码.提高系统的安全.

  1. Session共享
    当Ajax异步提交数据到后台控制器后,验证用户名和密码后正确,生成Token(使用UUID生成),将该Token做为key,同时将用户信息作为value保存至Redis.同时将该Token做为value保存至Cookie里面,设置声明周期,实现2天之内免登录的.保存登录状态.保存至Redis可以在分布式集群里面保持Session会话一致的.定时同步Sesison的延迟.

  1. JSR的参数校验
    使用JSR的自定义参数校验,实现用户账号,密码的验证.从验证逻辑中分离出来.

  1. 页面缓存和对象缓存
    通过在手动渲染得到的html页面缓存到redis.返回页面是html.设置produces="text/html"不走框架的渲染. 包括对用户信息,商品信息(商品列表,商品详情,商品库存),订单信息和token等数据进行redis缓存,设定生命周期(1分钟,商品库存是立即失效).利用缓存来减少对数据库的访问,大大加快查询速度.首先是取缓存,如果不存在就手动渲染. 依赖ThymeleafViewResolver.SpringWebContext.业务上下文数据.页面缓存.时间短1分钟.

  1. 页面静态化
    对商品详情页面和订单详情页面进行页面静态化处理.页面是静态的html.数据是从动态接口获取的,实现了前后端分离,静态页面无需连接数据库,打开的速度非常快.直接从在客户端了.html+ajax获取接口返回数据.先查询用户,在查询订单,在查询订单的编号.render()函数渲染页面.数据遍历放入table里面的相应的数据.

  1. 解决超卖
    更新库存的时候加判断条件stock_count>0.防止订单数目为负.解决超卖.没有使用同步机制就是直接获取库存数量.当临界的条件的是否比如商品只有一个的是否.这个是否都查看秒杀订单肯定是都为空的没有秒杀到,就减库存,下订单.库存就为负了. 在秒杀订单表里面,秒杀商品id和秒杀用户user_id建立唯一索引.防止同一用户秒杀到相同的商品. 生成订单写入缓存里面.判断是否秒杀成功.直接查询redis里面.JMeter压测超卖问题.5000个线程循环10次.50000个请求.1300左右QPS.当然根据机器的硬件环境有所不用.

  1. 异常处理
    自定义全局异常拦截器.控制器里面就不需要做参数异常校验了.拦截运行异常和绑定异常. 自定义全局异常,在业务代码判断直接抛出即可.然后就是全局异常拦截器拦截处理即可.易维护.

  1. 秒杀接口安全优化
    秒杀接口地址隐藏.秒杀开始前先去请求接口获取秒杀地址.带上一个PathVariable参数.添加生成秒杀地址的接口. 秒杀真实接口收到用户秒杀请求,先验证PathVariable参数.前面添加参数,Md5(UUID()+"123456").真正的path 后面加上user.id和商品id.时间限制60秒.保存至Redis里面.秒杀请求的时候就先校验path,就是对比Redis里面保存的地址.

  1. 图形验证码限流
    来到商品详情页面的时候,用户点击秒杀前要先输入验证码的,验证正确后,生成真实的秒杀地址.验证是数据公式,是ScriptEngineManager计算生成后的保存至Redis里面后,然后和客户端传来的进行校验.redis里面声明周期大约5分钟失效.

10.接口限流
实现接口一定时间内访问多少次,原始想法,接口写计时方法,记录访问次数.失效然后比较麻烦的. 放入缓存,一个用户访问次数.下一个一分钟缓存失效后又重新开始计数.点击秒杀.查询redis的访问次数.用户访问路径+用户id作为key.计数加1.大于5次就返回失败.返回太频繁了.

About


Languages

Language:Java 75.1%Language:HTML 23.7%Language:JavaScript 1.2%