Spring Cloud Gateway 之 限流
发布日期:2021-08-26 18:18:52 浏览次数:48 分类:技术文章

本文共 2762 字,大约阅读时间需要 9 分钟。

简介

在高并发的系统中,往往需要在系统中做限流,一方面是为了防止大量的请求使服务器过载,导致服务不可用,另一方面是为了防止网络***。

一般开发高并发系统常见的限流有:限制总并发数(比如数据库连接池、线程池)、限制瞬时并发数(如 nginx 的 limit_conn 模块,用来限制瞬时并发连接数)、限制时间窗口内的平均速率(如 Guava 的 RateLimiter、nginx 的 limit_req 模块,限制每秒的平均速率);其他还有如限制远程接口调用速率、限制 MQ 的消费速率。另外还可以根据网络连接数、网络流量、CPU 或内存负载等来限流。

限流算法

计数器

简单的做法是维护一个单位时间内的 计数器,每次请求计数器加1,当单位时间内计数器累加到大于设定的阈值,则之后的请求都被拒绝,直到单位时间已经过去,再将 计数器 重置为零。此方式有个弊端:如果在单位时间1s内允许100个请求,在10ms已经通过了100个请求,那后面的990ms,只能眼巴巴的把请求拒绝,我们把这种现象称为“突刺现象”。

常用的更平滑的限流算法有两种:漏桶算法令牌桶算法。下面介绍下二者。

漏桶算法

漏桶算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率。

Spring Cloud Gateway 之 限流

可见这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate)。因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流突发(burst)到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。

令牌桶算法

令牌桶算法 和漏桶算法 效果一样但方向相反的算法,更加容易理解。随着时间流逝,系统会按恒定 1/QPS 时间间隔(如果 QPS=100,则间隔是 10ms)往桶里加入 Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了。新请求来临时,会各自拿走一个 Token,如果没有 Token 可拿了就阻塞或者拒绝服务。

Spring Cloud Gateway 之 限流

令牌桶的另外一个好处是可以方便的改变速度。一旦需要提高速率,则按需提高放入桶中的令牌的速率。一般会定时(比如 100 毫秒)往桶中增加一定数量的令牌,有些变种算法则实时的计算应该增加的令牌的数量。

限流实现

在 Spring Cloud Gateway 上实现限流是个不错的选择,只需要编写一个过滤器就可以了。有了前边过滤器的基础,写起来很轻松。

Spring Cloud Gateway 已经内置了一个RequestRateLimiterGatewayFilterFactory,我们可以直接使用。

目前RequestRateLimiterGatewayFilterFactory的实现依赖于 Redis,所以我们还要引入spring-boot-starter-data-redis-reactive。

pom.xml

org.springframework.cloud
spring-cloud-starter-gateway
org.springframework.boot
spring-boot-starter-data-redis-reactive

application.yml

server:  port: 8080spring:  cloud:    gateway:      routes:        - id: limit_route          uri: http://httpbin.org:80/get          predicates:          - After=2019-02-26T00:00:00+08:00[Asia/Shanghai]          filters:          - name: RequestRateLimiter            args:              key-resolver: '#{@hostAddrKeyResolver}'              redis-rate-limiter.replenishRate: 1              redis-rate-limiter.burstCapacity: 3  application:    name: gateway-limiter  redis:    host: localhost    port: 6379    database: 0

在上面的配置文件,配置了 redis的信息,并配置了RequestRateLimiter的限流过滤器,该过滤器需要配置三个参数:

  • burstCapacity:令牌桶总容量。
  • replenishRate:令牌桶每秒填充平均速率。
  • key-resolver:用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。

IP限流

获取请求用户ip作为限流key。

@Beanpublic KeyResolver hostAddrKeyResolver() {    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());}

用户限流

获取请求用户id作为限流key。

@Beanpublic KeyResolver userKeyResolver() {    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));}

接口限流

获取请求地址的uri作为限流key。

@BeanKeyResolver apiKeyResolver() {    return exchange -> Mono.just(exchange.getRequest().getPath().value());}

欢迎关注我的公众号《程序员果果》,关注有惊喜~~

Spring Cloud Gateway 之 限流

转载于:https://blog.51cto.com/13698036/2395415

转载地址:https://blog.csdn.net/weixin_33894640/article/details/92724912 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:nodejs渐入佳境[13]-node回调操作
下一篇:51CTO技术社区13周年庆,技术图书、定制T恤免费领

发表评论

最新留言

感谢大佬
[***.8.128.20]2024年04月24日 17时06分22秒