技术要点:

* 掌握秒杀令牌的原理和使用方式

* 掌握秒杀大闸的原理和使用方式

* 掌握队列泄洪的原理是使用方式

缺陷原因:

* 秒杀下单接口会被脚本不停的刷

* 秒杀验证逻辑和秒杀下单接口强关联,代码冗余度高

* 秒杀验证逻辑复杂,对交易系统产生无关联负载

秒杀令牌原理:

* 秒杀接口需要依靠令牌才能进入

* 秒杀的令牌由秒杀活动模块负责生成

* 秒杀活动模块对秒杀令牌生产全权处理,逻辑收口

* 秒杀下单前需要先获得秒杀令牌

秒杀令牌实现:

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出现问题的时候切换到本地内存;也可负载均衡前提下队列本地内存。