1、计数器限流
计数器限流可以通过在内存中创建Map<key, AtomicInteger>类型容器实现,当key过多时这种方案不再适用,采用redis存储k-v并设置过期时间更为合适。但这种限流方案属于相对限流,即只能保证在绝对时间内的qps,无法保证相对时间内的qps。
例:10分钟只能访问3次,用计数器限流时,第9分59秒访问3次,第10分01秒仍然可以访问3次。对于9~11分钟的相对时间内,总共访问6次。
2、时间窗口
绝对限流方法—时间窗口,将整个时间范围均匀的划分为n等份的格子,每一份都有一个独立的计数器。当前时间会落在某一个格子内,随着时间推移,窗口不断向后滑动,通过这种方式就能控制一个时间段的绝对限流。但也会存在临界值问题,不过,当滑动窗口的格子划分的单位越小,整个窗口中的格子数量会越多,滑动窗口的向后移动就越平滑,限流的统计就会越精确。
3、令牌桶算法
主要思想
令牌桶算法的思想主要是:设定一个固定容量的池子,像池子内放入令牌,如果池子已满则丢弃准备放入的令牌。请求打进来时会先拿到令牌,如果请求获取令牌成功则执行具体业务方法,当桶内没有可用的令牌时,请求会被拒绝执行或者丢弃。
执行流程
实际执行流程:1、初始化令牌桶并设置最大令牌数,当桶内令牌达到阀值时,新添加的令牌会被拒绝或丢弃。2、根据限流大小,启动一条线程,并按照一定速率像令牌桶中不断添加新的令牌。2、任何限流范围内的请求,都会先获取到一个可用令牌,然后才会被处理。4、当一个请求获取到可用令牌后,才会执行真正的业务逻辑,执行完成后才会将令牌从桶中移除。5、令牌桶除了拥有最大令牌数,还拥有最小令牌数,当桶内令牌数小于最小阀值时,处理完请求不会移除令牌,而会将令牌还给令牌桶。
注意
注意:当桶内的令牌被一个请求获取后,此时并不会立马从桶内移除,该令牌会依旧停留在桶内,只不过该令牌的状态会从可用状态变为不可用状态,也就是其他请求无法再获取该令牌,真正移除令牌的工作,会在业务逻辑执行完成之后才触发。
4、漏桶限流方案
漏桶限流方法类似于日常生活中的漏斗,无论请求速率多快,处理速率都是恒定的。如果有些系统对稳定性要求较高,则可以采用漏桶算法。
5、成熟的业务实现
Guava 中的 RateLimiter 工具类:基于令牌桶实现的限流组件,并且对其进行了预热拓展。
Sentinel 中的匀速排队限流策略:基于漏桶思想的限流策略,内部采用队列进行实现。
Nginx 的 limit_req_zone 限流模块:基于漏桶思想的限流模块,实现网关层的限流控制。