限流

缘起

为了保证API的可用性,以及系统的可靠性,需要为API限速。不然,API请求量大到系统无法处理时就会出现系统变慢,甚至宕机的情况。常见的限速场景:

限速类型

请求限速

限制API在一秒中内能够处理的请求数量。如果超过这个数量,等待或者拒绝服务。通常情况下这个是首选。

并发限制

针对资源敏感的请求,比如CPU密集型API,进行并发限制,限制某一时刻最多只有有限个请求正在被处理。防止因为这些请求占用资源,导致其他请求得不到处理。

基于资源利用率限速

针对不同的请求分配了不同百分比的资源,当某一类请求超载时,对这类请求限速。

基于worker限速

这个是基于代码特征的限速。每类API通过不同的worker线程负责处理,当worker线程中出现请求堆积时进行限速。

限速结果

http服务的话按照场景返回429或者503。

常用算法

计数

单位时间内计数,超过这个数量时,拒绝服务,每个单位时间开始后计数清零。缺点是在时间边界处,会超过上限。比如,每秒限速100,在0.9s的时候来了100个请求全部得到处理,在下一秒0.1s来了100个请求。在0.9s到1.1s这个范围小于1s,但是请求达到了200。

 0.1s 0.2s 0.3s 0.4s 0.5s 0.6s 0.7s 0.8s 0.9s 0.1s 0.2s
+----+----+----+----+----+----+----+----+----+----+----+---
| 0  | 0  | 0  | 0  | 0  | 0  | 0  | 0  | 100| 100| 0  | 0 
+----+----+----+----+----+----+----+----+----+----+----+---

队列

请求过来的时候,先如队列,处理逻辑处理队列中的请求。

漏桶

有一个容量固定的桶,桶中的请求以恒定的速率被处理。请求过来的时候,尝试进入桶,当桶满时被丢弃。本质上是队列后面加一个速率限制器。

漏桶还有一个变形,在漏桶前面加一个队列。当桶满的时候,先放入队列,这样可以保留一部分请求。

令牌桶

以恒定的速率向桶中加入token,当请求过来的时候从桶中获取token。如果桶空了,请求等待或者丢弃。相比漏桶令牌桶还可以做蓄水,当桶满的时候可以预留一部分token,可以做到突发(burst)的请求。

实现

Guava中的RateLimter是一个平滑的基于令牌桶的实现,同时还实现了warm up特点的一个Ratelimiter

← guava中RateLimiter的设计 分布式ID生成算法 →
存档 关于