限流是保护高并发系统的三把利器之一,另外两个是缓存和降级。
限流基础算法
- 漏桶算法
- 流入速度任意。
- 流出速度固定。
- 请求到来时,放入队列,出口侧按固定速度消费。
- 无论积压多少请求,出口侧都按固定速度匀速处理。
- 队列满时,阻塞、或丢弃。
- 令牌桶算法。
- 通过控制令牌生成速度,达到流量平稳。
- 请求/调用 到达时,从桶拿取令牌,拿不到时,阻塞或丢弃。
- 若消费方短暂中断,或某个处理比较耗时,而积累了令牌,则可能产生一波突发处理。
- 二者对比:
- 漏桶限制的是常量流出速率。
- 令牌桶限制的是平均流入速率。
Guava RateLimiter
- RateLimiter使用令牌桶算法,会进行令牌的累积。
- 令牌的产生是匀速的,若令牌的消耗较快,则整个调用过程也会是平衡的均匀的。
final void doSetRate(double permitsPerSecond, long nowMicros) {
resync(nowMicros);
double stableIntervalMicros = SECONDS.toMicros(1L) / permitsPerSecond;
this.stableIntervalMicros = stableIntervalMicros;
doSetRate(permitsPerSecond, stableIntervalMicros);
}
- permitsPerSecond:每秒产生的令牌数。
- SECONDS.toMicros:将 1 秒转化为毫秒。
- stableIntervalMicros:生产令牌的稳定间隔毫秒数。
补充:
如不想使用框架,且对平稳性要求不高,也可用JDK自带工具原生写一个:
try {
if (atomic.incrementAndGet() > 限流数) {
// 拒绝请求
}
// 处理请求
} finally {
atomic.decrementAndGet();
}
参考:https://zhuanlan.zhihu.com/p/60979444
https://blog.youkuaiyun.com/l1394049664/article/details/82050066。