流量削峰
浪涌洪峰流量。第一秒流量涌入的问题。使用平滑的方式过度掉,使系统性能平滑提升。
普通的下单:
- 下单接口会被脚本不停刷,脚本会比用户手速快
- 秒杀验证逻辑和秒杀下单接口强关联,代码冗余度高
秒杀令牌
- 秒杀接口需要依靠令牌才能进入
- 令牌由秒杀活动产生
- 秒杀活动对令牌管理
- 秒杀下单前需要先让用户获得令牌
提供一个令牌接口,用户下单前,调用这个接口,生成了令牌后,存入redis。
下单的时候再判断令牌是否在redis里。
缺点:没有做数量限制
令牌相关的
- 这个大闸是其中一种做法
- 令牌存放的表 xx_token
- id、日期、业务号、令牌余量(大闸)、时间
- 这样用表的好处是可以实时查看。
-
update sk_token
set `count` = if (`count` < #{decreaseCount}, 0, `count` - #{decreaseCount})
where `date` = #{date}
and train_code = #{trainCode}
and `count` > 0
- 令牌也可以放到内存中使用。
令牌的初始化
初始化车次的时候就初始化令牌信息。
秒杀大闸
基于秒杀令牌的原理,控制令牌的发放数量。
一般是有多少库存,就比库存多发放一点点。 这个数在保存库存的时候存。
库存售罄也前置到这里。
每次发放令牌之后,大闸数量-1,小于0之后,不再发放。
缺点:
如果库存大,还是无法一瞬间拦截大量请求,而且商品的种类也多,大闸就种类也多。
队列泄洪
使用队列
队列减少上下问切换,减少资源竞争锁的浪费。
依靠排队和校友拥塞窗口程度调整队列释放流量大小
支付宝的银行网关队列,就是用队列的。
ExecutorService executorService;
@PostConstruct
public void init(){
//只有20个线程的线程池
executorService = Executor.newFixedThreadPool(20);
}
Future f = executorService.submit(new Callable){
下单。
减库存。
}
f.get();
这样 同一时间 只有20个线程被执行 队列化泄洪。
这个只是简单的一种方式,本地的一种实现。多台机器就会有多个线程池来实现泄洪。
所以本地和分布式都有,本地实现效率还是高。负载有可能不均衡。
正常用分布式,降级时为本地。是一种实现方案。