-
两次md5校验保证无法通过彩虹表倒反推出用户密码
两次md5
- 用户端:pass = md5 (明文 + 固定salt)
- 服务端:pass = md5 (用户输入 + 随机salt)
导入依赖
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.6</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </dependency>
-
JSR303参数校验
@NotNull 验证是否为空
@Length(min=32) 验证长度是否为32
自定义验证器@IsMobile实现ConstraintValidator接口(通过正则表达式验证手机号是否合法)
<!--自定义参数校验器+全局异常处理器--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
-
全局异常处理器
定义全局异常GlobalException拦截异常,继承自RuntimeException
-
分布式Session
- 在分布式集群的条件上,用户的Session存储和同步是个问题。
- 本项目采用redis对token进行缓存,这里key为
prefix + token,value为user对象 - 客户端每次访问服务款携带Cookie,服务端可以通过客户端Cookie的token获取Session
- Cookie的过期时间以用户最后一次登录为准,每登录一次修改过期时间,默认过期时间是两天
- 通过
UserArgumentResolver的回调功能将Controller需要的参数注入,减少冗余代码
- 压测商品列表接口
/goods/to_list
1000个线程循环压测10次后的结果:
做页面优化前:
做页面缓存优化后:
- 压测秒杀接口
/seckill/do_seckill
这边需要通过UserUtil工具类生成多个用户token,然后通过jmeter配置元件->csv数据文件设置导入token文件
redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000100个并发连接 10万个请求
可以达到10万多QPS
redis-benchmark -h 127.0.0.1 -p 6379 -q -d 100存取大小为100字节的数据包
redis-benchmark -t set,lpush -n 100000 -q只测试某些操作的性能
redis-benchmark -n 100000 -q script load "redis.call('set','foo','bar')"只测试某些数值存取的性能
- 商品列表页和详情页静态资源缓存在redis中,过期时间为一分钟,每次先去redis里面取,redis中查不到再去mysql访问,并更新缓存
- 动态资源通过前端js的ajax动态加载
- SeckillUserService和OrderService根据id查询的service中对user对象和订单详情对象进行了对象缓存,这样不用每次去访问mysql查询,直接先查询缓存即可, 更新的缓存的时候需要注意先后顺序,一定是先更新数据库再更新缓存。
- SQL加入库存判断,更新库存在库存量大于0时才更新
update seckill_goods set stock_count=stock_count-1 where goods_id=#{goodsId} and stock_count > 0- 防止一个用户同事秒杀一个商品两次,为seckill_order表的user_id和goods_id添加联合btree索引
alter table seckill_order add unique key(user_id,goods_id);- 多个用户同时进行秒杀操作,同时判断库存不为0,然后均写入订单,出现下订单详情异常需要在
SeckillService中加入如下判断:
//减库存 下订单 写入秒杀订单
boolean success = goodsService.reduceStock(goods);
if (success) {
return orderService.createOrder(user, goods);
}- 系统初始化,把商品库存数量加载到Redis
- 收到请求,Redis预减库存,库存不足,直接返回,否则进入3
- 请求入队,立即返回排队中
- 请求出队,生成订单,减少库存
- 客户端轮询,是否秒杀成功
- 秒杀接口实现Spring的
InitializingBean并重写afterPropertiesSet方法,在初始化SeckillController这个Bean时会同步一些数据库和缓存的内存 - 当预减库存超量时,也即预减库存发现小于0时,再调用一次
afterPropertiesSet方法同步一下数据库和缓存的库存
接口优化之前对秒杀接口压测:(1000个线程循环10次)
优化之后:







