限流-最佳实践

2,403 阅读3分钟

对比基于时间窗口的限流算法,令牌桶和漏桶算法对流量整形效果比时间窗口算法要好很多,但是并不是整形效果越好就越合适,对于没有提前预热的令牌桶,如果做否决式限流,会导致误杀很多请求。上述算法中当 n 比较小时,比如 50,间隔 20ms 才会向桶中放入一个令牌,而接口的访问在 1s 内可能随机性很强,这就会出现:尽管从曲线上看对最大访问频率的限制很有效,流量在细时间粒度上面都很平滑,但是误杀了很多本不应该拒绝的接口请求。

所以令牌桶和漏桶算法比较适合阻塞式限流,比如一些后台 job 类的限流,超过了最大访问频率之后,请求并不会被拒绝,而是会被阻塞到有令牌后再继续执行。对于像微服务接口这种对响应时间比较敏感的限流场景,会比较适合选择基于时间窗口的否决式限流算法,其中滑动时间窗口限流算法空间复杂度较高,内存占用会比较多,所以对比来看,尽管固定时间窗口算法处理临界突发流量的能力较差,但实现简单,而简单带来了好的性能和不容易出错,所以固定时间窗口算法也不失是一个好的微服务接口限流算法。


以上是各种优劣的对比。

上面说的,拒绝,就是放弃请求。阻塞,就是等待,稍后再处理请求,而不会丢弃请求。

最佳实践

拒绝算法。即时间算法。

拒绝

因为阻塞算法只适合每个请求都必须要处理的场景。而拒绝算法,适合限流,而且实现简单。

当然,阻塞算法也可以放弃请求,即拒绝请求。只不过,适合的应用场景有区别。因为漏桶算法是按固定速度来处理请求,而时间算法是按固定时间来处理请求。

即,一个是1ms处理一个请求,一个是1s处理1000个请求。

这两个有什么区别呢?就是我们的需求,应该是1ms可以处理10个请求,而不是1个请求。而如果是采用时间算法,那么1s内的任何1ms,都可以处理10个请求。但是,如果是漏桶算法,那么就只能处理1个请求,其他9个请求处理不了,就只能丢弃请求了。

本质的区别是,两个维度。当然,如果硬要去解决的话,漏桶算法也可以做到1ms处理10个请求,当然归根结底,还是适用的应用场景有一些区别的,不是说一种算法就只能解决一种算法的问题,而解决不了另外一种算法的问题,关键是适合。

阻塞

阻塞其实也是限流,本质上是控制流量。

阻塞,就是必须要消费这些数据。比如,支付系统里的实名认证接口,每一个请求都是必须要处理的。但是你的线程池里的阻塞队列是1000,超过了就只能先阻塞,等队列数据被消费了,再入队列。

参考

mp.weixin.qq.com/s/k9tm-4lBw…