前言
本文接着聊Sentinel的QPS流控效果基于漏桶算法的排队等待模式,Sentinel排队等待为什么只支持QPS在1000以下?另外,Sentinel在新版版中还提供了一种预热+等待的模式,这种模式执行逻辑是怎么样的?
一、漏桶算法含义
漏桶算法(Leaky Bucket):随机突发流量通过漏桶后以稳定的速率流出,起到流量控制和平滑作用,如下图所示。
二、排队等待模式
Sentinel中的排队等待由RateLimiterController实现,通过控制请求通过的时间间隔来实现达到匀速的目的。
代码逻辑 @1 计算请求通过的间隔时间 假如设置的阈值为count=100即每秒允许100个请求,每次通过一个请求acquireCount=1,套入公式costTime=10。即两次请求的时间间隔为10秒 @2 计算这次请求通过的预期时间=上次请求通过的时间+时间间隔 @3 当前时间大于预期时间,则允许通过并更新上次请求时间戳 @4 当前时间小于预期时间,则需要等待;计算需要等待的时间 @5 需要等待的时间大于超时时间则拒绝,默认超时时间为500毫秒 @6 再算一遍等待时间,算法跟第4步一样,并再次判断是否超过等待时间 @7 线程sleep等待时间后允许请求通过
三、匀速模式局限
Sentinel等待模式为什么只支持1000以内QPS?文章开头提出的问题。下面看下时间间隔计算公式,每次通过一个请求acquireCount=1。
long costTime = Math.round(1.0 * (acquireCount) / count * 1000);
下个请求的预期通过时间为:
long expectedTime = costTime + latestPassedTime.get();
随着阈值count即一秒期望通过的请求数,下面观察随着阈值的变化,时间间隔变化情况。
count | costTime | expectedTime |
---|---|---|
100 | 10 | latestPassedTime.get() + 10 |
1000 | 1 | latestPassedTime.get() + 1 |
2000 | 1 | latestPassedTime.get() + 1 |
3000 | 0 | latestPassedTime.get() + 0 |
10000 | 0 | latestPassedTime.get() + 0 |
由上表看出阈值count大于1000小于2000,时间间隔一致为1毫秒,而大于2000后,时间间隔则掉为0,即后面的所有判断将失效。因此Sentinel提供的匀速器只支持QPS在1000以内的请求场景。
四、预热模式+排队等待
Sentinel还提供一种预热+排队等待相结合的限流模式,也就是令牌桶和漏桶相结合的模式,示意图如下:请求的通过需要从令牌桶中获取令牌,获取令牌的流量需要经过漏桶匀速通过。
源码分析
备注 整体可以分配两个部分,上部分基于令牌桶计算部分,下部分基于漏桶计算部分。
@1 warningToken令牌桶中的一个阈值,超过该值时开启预热 @2 小于warningToken不开启预热,根据阈值计算下个请求通过时距离上个请求的时间间隔 @3 warmingQps根据斜率计算出预热时的Qps @4 计算预热时下个请求通过时距离上个请求的时间间隔 @5 这部分与上面匀速排队逻辑一致
小结:预热模式+排队等待模式比单纯的预热模式,在请求通过是增加了请求之间时间间隔的判断;相比单纯的排队模式,在时间间隔上更加灵活,根据预热时的Qps计算时间间隔。
作者丨梁勇 来源丨瓜农老梁