针对秒杀项目做的一些优化
Posted 赵jc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了针对秒杀项目做的一些优化相关的知识,希望对你有一定的参考价值。
秒杀
做了一个秒杀项目,并对其做了一定的优化!
业务逻辑
数据库的设计
- 为什么将秒杀的商品单独建一张表(秒杀表)而不再商品表添加一个字段来判断呢,因为今天可能是秒杀,明天可能是9.9包邮,这样的话导致商品表越来越难以维护
一些全局配置
- 全局异常处理
- 错误信息描述
JSR303参数验证(手机号)
使用JSR对参数进行验证(这里以手机号为例)
登录
-
用ThreadLocal存储用户的信息,多线程情况下保证用户的安全(收到请求,并且到相应完成都是一个请求(一个线程)所以使用ThreadLocal)
-
商品页、商品详情页 需要判断session状态所以我们实现一个ArgumentResolver(controller会带很多参数(Respone、Request),框架会回调这个ArgumentResolvers方法,遍历controller的参数并进行赋值)
-
进行登录验证,有时候手机端token并不是放在cookie中传递,而直接放在参数中传递(兼容性)
-
秒杀场景肯定不可能一个服务器:第一个用户session放在第一个服务器,用户第二次登录session放在了第二台服务器,此时导致session失效,所以需要用一个redis单独管理我们的session(分布式session)
- 但容器当中的session过期规则是最后一次的访问时间加上过期时间,所以我们需要重新设置cookie
秒杀
秒杀主要分为以下几步
第一步:判断商品库存是否充足
第二步:判断是否已经秒杀到了
以下三步属于原子操作,需要放在一个事务中进行
第三步:减库存
第四步:下订单
第五步:写入秒杀订单
关于超卖问题的解决
- 数据库加唯一索引:防止用户重复购买
- SQL加库存数量判断:防止库存变为负数
优化
优化前QPS:5000x10 1306
优化后QPS:5000x10 2260
优化的核心思路便是:减少对数据的访问
这里没有设计数据库的分库分表。
缓存优化
Redis的封装
- 使用JedisPool池化技术方便多次使用,并对Redis进行封装,方便使用
- redis一个key获取一个value,只用string来当key的话不利于维护,所以引入了对应的前缀keyPrefix,每个模块对应自己的keyPrefix方便管理,通过自己模块的变量不同来进行区分
页面缓存
将整个页面在Redis中缓存,减少对数据库的查询和页面的渲染次数
-
取缓存
-
手动渲染模板(使用ThymeleafViewResolver来帮助我们手动渲染页面)
- 结果输出
对象缓存
将秒杀用户的对象缓存起来,方便使用
客户端的缓存(页面静态化+前后端分离)
不再使用thymeleaf,而使用AJAX和jQuery(高级的有vue.js)
接口优化
用rabbitmq将同步下单改为异步下单
- 系统初始化,把商品库存数量加载到Redis中(实现InitializingBean接口,重写afterPropertiesSet将商品的库存加载到Redis缓存中)
- 收到请求,Redis预减库存,库存不足,直接返回,否则进入队列(但如果一次性来很多请求,假如库存有10个,但一次性来了100个请求,11以后的请求都回去预减库存,但此时库存已经为0了,所以加了一个localGoodsOverMap来做内存标记减少对redis的访问)
-
请求入队,立即返回排队中,此时并不是秒杀成功(就像12306抢票,正在抢票中,请等待,并不表示一定会成功,也有可能失败)
-
请求出队,生成订单,减少库存(核心:异步下单)在receive当中真正去判断库存、创建订单
- 客户端轮询,是否秒杀成功(与上一步是并行操作)
安全方面
明文密码两次MD5处理
因为使用的是http协议,所以在网络传输时有一定的安全问题,所以使用了MD5加密的方式,但现在有很多MD5反推到工具,所以使用了两次MD5+salt(密匙)的方式来进行加密。
- 第一步:客户端存储一个固定的salt,用户输入密码后,用salt和MD5加密后的密码用form表单的方式传送给后端
- 第二步:后端拿到客户端传来的密码后,在使用用户自己填的salt和MD5进行二次加密
- 将两次加密后的密码存储到数据库中
秒杀接口地址隐藏
思路:秒杀开始前,先去请求接口获取秒杀地址
- 前端先通过后端获取一个任意的字符串来当做path(createSeckkillPath),之后的秒杀请求都需要带上这个path参数
- 改造秒杀接口(带上pathvariable参数),后端检查前端的path和之前返回给前端的path是否相同,如果相同才执行以下的逻辑
接口限流
使用了注解加拦截器的方式来限制访问次数
以上是关于针对秒杀项目做的一些优化的主要内容,如果未能解决你的问题,请参考以下文章