解决方案:限流算法
关键词
- 计数器法,漏桶(单位时间内),令牌桶算法(并发)
- gateway 默认使用redis的RateLimter限流算法(lua实现)
- nginx限流(ngx_http_limit_req_module,ngx_http_limit_conn_module)
一、常见限流算法
常见的限流算法有计数器算法、漏桶算法和令牌桶算法。
- 计数器法
计数器算法 简单粗暴。该算法会维护一个counter,规定在单位时间内counter的大小不能超过最大值,每隔固定时间就将counter的值置零。如果这个counter大于设定的阈值了,那么系统就开始拒绝请求以保护系统的负载。
- 漏桶算法
在漏桶算法中,我们会维护一个固定容量的桶,这个桶会按照指定的速度漏水。如果这个桶空了,那么就停止漏水;请求到达系统就类似于将水加入桶中,这个速度可以是匀速的也可以是瞬间的,如果这个桶满了,就会忽略后面来的请求,直到这个桶可以存放多余的水。漏桶算法的好处是可以将系统的处理能力维持在一个比较平稳的水平,缺点是在瞬间流量过来时,会拒绝后续的请求流量。一般来说,代码中会使用一个队列实现“漏斗”的效果,当请求过多时,队列中的请求就开始积压,当队列满了之后,系统就会开始拒绝请求。(相当于一个队列)
如图下图所示,把请求比作水,水来了都先放进桶里,并以限定的速度出水,当水来得过猛而出水不够快时就导致水直接溢出,即拒绝服务。

- 令牌桶算法
令牌桶算法和漏桶算法效果一样,但思路相反:随着时间的流逝,系统会按照指定速度往桶里添加token,每来一个新请求,就从桶里拿走一个token,如果没有token可拿就拒绝服务。这种算法的好处是便于控制系统的处理速度,甚至可以通过统计信息实时优化令牌桶的大小。
令牌桶算法是比较常见的限流算法之一,大概描述如下:
1)所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
2)根据限流大小,设置按照一定的速率往桶里添加令牌;
3)桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
4)请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;

从理论上来说,令牌桶算法和漏桶算法的不同之处在于处理瞬间到达的流量的不同:令牌桶算法由于在令牌桶里攒了很多令牌,因此在大流量到达的瞬间可以一次性将队列中所有的请求都处理完,然后按照恒定的速度处理请求;
漏桶算法则一直有一个恒等的阈值,在大流量到达的时候,也会将多余的请求拒绝。
在Nginx这种基本没什么业务逻辑的网关中,自身的处理不会是瓶颈,在这种场景下,就比较适合使用令牌桶算法了。
二、限流实践
RateLimiter是guava中concurrent包下的一个限流工具类,使用了令牌桶算法。
它支持两种令牌获取接口:
- 获取不到一直阻塞;
- 在指定时间内获取不到就阻塞,超过这个时间就返回获取失败。
(1)RateLimiter的使用。
在下面的这个例子中,我们希望每秒最多2000次业务操作,因此先初始化令牌桶的大小为2000,在执行业务操作之前,先调用acquire()获取令牌,如果获取不到就阻塞。

如果请求可以丢弃,并且在某种程度上需要这种快速失败,那么就不能使用acquire()方法,为了避免源源不断的请求将整体的系统资源耗尽,就需要使用 tryAcquire()方法。下面是针对tryacquire()的示例,还可以使用带超时参数的 tryAcquire()方法,在指定时间内获取不到令牌再返回false。

(2)RateLimiter的设计思路。
RateLimiter的主要功能是通过 限制请求流入的速度 来提供稳定的服务速度。
实现QPS速度最简单的方式就是记住上一次请求的最后授权时间,然后保证1/QPS秒内不允许请求进入。例如QPS=5,如果我们保证最后一个被授权请求之后的200ms内没有请求被授权,那么就达到了预期的速度。如果一个请求现在过来但最后一个被授权请求是在100ms之前,那么我们就要求当前这个请求等待100ms,按照这个思路请求15个新令牌(许可证)就需要3秒。(控制申请令牌的速度)
三、网关限流实现( 底层实现redis的RateLimter限流算法 [lua实现] )
需求:每个ip地址1秒内只能发送1次请求,多出来的请求返回429错误。
(1)spring cloud gateway 默认使用redis的RateLimter限流算法来实现。所以我们要使用首先需要引入redis的依赖
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<version>2.1.3.RELEASE</version>

本文探讨了计数器、漏桶和令牌桶三种限流算法在网关(如Spring Cloud Gateway与Nginx)的应用,重点讲解了RateLimiter的Guava实现和Redis Rate Limiter lua脚本,以及如何通过Nginx的ngx_http_limit_req_module和ngx_http_limit_conn_module模块进行限流配置。
最低0.47元/天 解锁文章
2066

被折叠的 条评论
为什么被折叠?



