在开发高并发系统时,有很多种方法可用来保护系统:缓存、降级、限流等。
限流就是通过对并发访问/请求进行限速或一个时间窗口内的请求进行限速,从而达到保护系统的目的。一般系统可以通过压测来预估能处理的峰值,一旦达到设定的峰值阀值,则可以拒绝服务(定向错误页或告知资源没有了)、排队或等待(例如:秒杀、评论、下单)、降级(返回默认数据)
限流不能乱用,否则正常流量会出现一些奇怪的问题,从而导致用户抱怨。
常见限流算法:技术器、令牌桶和漏桶算法。
计数器是最简单粗暴的算法。例如:一个服务每秒能处理100个请求。设置一个1s的滑动窗口,窗口有10个格子,每个格子100ms,每100ms移动一次,每次移动都记录当前服务请求的次数。内存中保存最近10次的次数(LinkedList)。格子每次移动的时候判断一次,最后一个格子和第一个格子的次数是否相差100,如果超过,则进行限流。
当格子划分的越多,那么滑动窗口的滚动越平滑,限流的统计就会越精确。
计数器的实现简单,但是是平均分配1秒钟的请求,然而实际情况中的请求往往是动态的,流量不平滑的。
令牌桶算法是一个存放固定容量令牌(token)的桶,按照固定速率往桶里添加令牌。令牌桶的主要概念如下:
令牌桶根据放令牌的速率(r tokens/s)去控制输出的速率(to network)
令牌桶的另外一个好处是可以方便的改变速度. 一旦需要提高速率,则按需提高放入桶中的令牌的速率. 一般会定时(比如100毫秒)往桶中增加一定数量的令牌, 有些变种算法则实时的计算应该增加的令牌的数量.
漏桶( Leaky Bucket
)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率。
漏桶作为计量工具时,可用于流量整形和流量控制,漏桶的主要概念如下:
漏桶可以看做固定容量、固定流出速率的队列,漏桶限制的是请求的流出速率,漏桶中装的是请求
因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流突发( burst
)到端口速率.因此,漏桶算法对于存在突发特性的流量来说缺乏效率.
|
令牌桶 |
漏桶 |
---|---|---|
请求何时拒绝 | 固定速率往桶中添加令牌,如果桶中令牌不够,则拒绝新请求 | 流入请求速率任意,常量固定速率流出请求。当流入请求数积累到漏桶容量时,则拒绝新请求 |
速率限制 | 限制平均流入速率,允许一定程度的突发请求(支持一次拿多个令牌) | 限制常量流出速率(流出速率是固定值),从而平滑突发流入速率 |
参考:
基于Redis的限流系统的设计