Spring Cloud Gateway 之 限流

简介

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

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

限流算法

计数器

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

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

漏桶算法

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

Spring Cloud Gateway 之 限流

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

令牌桶算法

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

Spring Cloud Gateway 之 限流

令牌桶的另一个好处是能够方便的改变速度。一旦须要提升速率,则按需提升放入桶中的令牌的速率。通常会定时(好比 100 毫秒)往桶中增长必定数量的令牌,有些变种算法则实时的计算应该增长的令牌的数量。数据库

限流实现

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

Spring Cloud Gateway 已经内置了一个RequestRateLimiterGatewayFilterFactory,咱们能够直接使用。服务器

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

pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifatId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

application.yml

server:
  port: 8080
spring:
  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。

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

用户限流

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

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

接口限流

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

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

欢迎关注个人公众号《程序员果果》,关注有惊喜~~
Spring Cloud Gateway 之 限流

相关文章
相关标签/搜索