技术要点:
* 掌握秒杀令牌的原理和使用方式
* 掌握秒杀大闸的原理和使用方式
* 掌握队列泄洪的原理是使用方式
缺陷原因:
* 秒杀下单接口会被脚本不停的刷
* 秒杀验证逻辑和秒杀下单接口强关联,代码冗余度高
* 秒杀验证逻辑复杂,对交易系统产生无关联负载
秒杀令牌原理:
* 秒杀接口需要依靠令牌才能进入
* 秒杀的令牌由秒杀活动模块负责生成
* 秒杀活动模块对秒杀令牌生产全权处理,逻辑收口
* 秒杀下单前需要先获得秒杀令牌
秒杀令牌实现:
1、分开验证(活动、用户等相关校验)接口和交易接口,在验证接口生成token(UUID即可,返回token value不返回key);
2、redisTemplate.opsForValue().set("promo_token_"+活动ID+"_userid_"+用户ID+"_itemid_"+商品ID,UUID) 等方法并设置过期时间并存入redis等缓存
3、交易接口只需要校验秒杀令牌是否有效
秒杀大闸原理:
* 依靠秒杀令牌的授权原理定制化发牌逻辑做到大闸功能
* 根据秒杀商品初始库存颁发对应数量令牌,控制大闸流量(因抢到不一定买,可比库存更多的令牌数量,如库存的3倍)
* 用户风控策略前置到秒杀令牌发放中
* 库存售罄判断前置到秒杀令牌发放中
秒杀大闸实现:
* 发布活动在库存同步redis时,讲大闸的限制数字设置到redis当中
* redisTemplate.opsForValue().set("promo_door_count_"+活动ID, 活动库存*3)
* 在生成秒杀令牌token前,获取秒杀大闸的数量-1
* long result = redisTemplate.opsForValue().increment("promo_door_count_"+活动ID, -1)
* 若result>=0,允许生成秒杀令牌
秒杀令牌仍存在缺陷:
* 浪涌流量涌入后系统无法应对
* 多库存、多商品等令牌限制能力弱
队列泄洪原理:
* 排队有些时候比并发更高效(例如redis单线程模型,innodb mutex key等)
* 依靠排队去限制并发流量
* 依靠排队和下游拥塞窗口程度调整队列释放流量大小
* 支付宝银行网关队列举例
队列泄洪实现:
// 下单业务控制类
private ExecutorService executorService;
@PostConstruct
public void init(){
executorService = Executors.newFixedThreadPool(20); //创建20线程的线程池
}
//以下为下单方法里面代码
//同步调用线程池的submit方法
//拥塞窗口为20的等待队列,用来队列化泄洪
Future<Object> future = executorService.submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
//业务方法:加入库存流水init状态
//业务方法:完成对应的下单事务型消息机制
return null;
}
});
//try catch future
future.get();
* 本地:将队列维护在本地内存中
* 分布式:将队列设置到外部redis内
说明:队列维护在本地内存性能更高,推荐使用;redis单机会有性能瓶颈,需要redis集群保障性能和可访问性,可在redis出现问题的时候切换到本地内存;也可负载均衡前提下队列本地内存。