限流算法
常见的限流算法有计数器算法、漏桶算法和令牌桶算法。
计数器法
计数器算法“简单粗暴”。该算法会维护一个counter,规定在单位时间内counter的大小不能超过最大值,每隔固定时间就将counter的值置零。如果这个counter大于设定的阈值了,那么系统就开始拒绝请求以保护系统的负载。
漏桶算法
在漏桶算法中,我们会维护一个固定容量的桶,这个桶会按照指定的速度漏水。如果这个桶空了,那么就停止漏水;请求到达系统就类似于将水加入桶中,这个速度可以是匀速的也可以是瞬间的,如果这个桶满了,就会忽略后面来的请求,直到这个桶可以存放多余的水。漏桶算法的好处是可以将系统的处理能力维持在一个比较平稳的水平,缺点是在瞬间流量过来时,会拒绝后续的请求流量。一般来说,代码中会使用一个队列实现“漏斗”的效果,当请求过多时,队列中的请求就开始积压,当队列满了之后,系统就会开始拒绝请求。
如图下图所示,把请求比作水,水来了都先放进桶里,并以限定的速度出水,当水来得过猛而出水不够快时就导致水直接溢出,即拒绝服务。
令牌桶算法
令牌桶算法和漏桶算法效果一样,但思路相反:随着时间的流逝,系统会按照指定速度往桶里添加token,每来一个新请求,就从桶里拿走一个token,如果没有token可拿就拒绝服务。这种算法的好处是便于控制系统的处理速度,甚至可以通过统计信息实时优化令牌桶的大小。下图清楚地说明了这个算法。
从理论上来说,令牌桶算法和漏桶算法的不同之处在于处理瞬间到达的大流量的不同:令牌桶算法由于在令牌桶里攒了很多令牌,因此在大流量到达的瞬间可以一次性将队列中所有的请求都处理完,然后按照恒定的速度处理请求;漏桶算法则一直有一个恒等的阈值,在大流量到达的时候,也会将多余的请求拒绝。在Nginx这种基本没什么业务逻辑的网关中,自身的处理不会是瓶颈,在这种场景下,就比较适合使用令牌桶算法了。
限流实践
RateLimiter是guava中concurrent包下的一个限流工具类,使用了令牌桶算法,它支持两种令牌获取接口:获取不到一直阻塞;在指定时间内获取不到就阻塞,超过这个时间就返回获取失败。
引自《高可用可伸缩微服务架构:基于Dubbo、Spring Cloud和Service Mesh》
网友评论