服务化过程中各种流控策略
计数器
滑动窗口
控制并发
信号量
Semaphore semphore = new Semaphore(10);
if(semphore.getQueueLength() > 10){
//等待队列阀值为10时
return;
}
try {
semphore.acquire();
//干活
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
semphore.release();//释放
}
控制速率
令牌桶
在 Wikipedia 上,令牌桶算法是这么描述的:
- 每秒会有 r 个令牌放入桶中,或者说,每过 1/r 秒桶中增加一个令牌
- 桶中最多存放 b 个令牌,如果桶满了,新放入的令牌会被丢弃
- 当一个 n 字节的数据包到达时,消耗 n 个令牌,然后发送该数据包
- 如果桶中可用令牌小于 n,则该数据包将被缓存或丢弃
令牌桶控制的是一个时间窗口内的通过的数据量,在 API 层面我们常说的 QPS、TPS,正好是一个时间窗口内的请求量或者事务量,只不过时间窗口限定在 1s 罢了。Java 语言,可以借助 Guava 的 RateLimiter 来实现基于令牌桶的流控。RateLimiter 对简单的令牌桶算法做了一些工程上的优化,具体的实现是 SmoothBursty。SmoothBursty 有一个可以放 N 个时间窗口产生的令牌的桶,系统空闲的时候令牌就一直攒着,最好情况下可以扛 N 倍于限流值的高峰而不影响后续请求。RateLimiter 允许某次请求拿走超出剩余令牌数的令牌,但是下一次请求将为此付出代价,一直等到令牌亏空补上,并且桶中有足够本次请求使用的令牌为止。
需要注意的是,RateLimiter 的另一个实现 SmoothWarmingUp,就不是令牌桶了,而是漏桶算法。
出于简单起见,RateLimiter 中的时间窗口能且仅能为 1s,如果想搞其他时间单位的限流,只能另外造轮子。
漏桶
- “漏桶算法”能够强行限制数据的传输速率,
- “令牌桶算法”在能够限制数据的平均传输数据外,还允许某种程度的突发传输。在“令牌桶算法”中,只要令牌桶中存在令牌,那么就允许突发地传输数据直到达到用户配置的上限,因此它适合于具有突发特性的流量。