Springcloud Gateway之限流

1.计数器

维护一个单位时间内的计数器(例如:设置1s内允许请求次数10次),表示为时间单位1秒内允许计数次数最高为10,每次请求计数器加1,当单位时间内计数器累加到大于设定的阈值(10),则之后的请求都被拒绝,直到单位时间(1s)已经过去,再将计数器 重置为零。缺点:如果在单位时间1s内允许100个请求,在10ms已经通过了100个请求,那后面的990ms所接收到的请求都会被拒绝,我们把这种现象称为“突刺现象”。

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

2.漏桶算法

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

Springcloud Gateway之限流_第1张图片

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

3.令牌桶算法

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

 Springcloud Gateway之限流_第2张图片

4.限流实现

在 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: 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 对象。

4.1 IP限流

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

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

 

4.2 用户限流

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

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

 

4.3 接口限流

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

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

 

 

·计数算法适合流量突发情况(瞬间突发)

·令牌桶适合均速,无法获取令牌的请求直接拒绝

·漏桶算法适合均速并且可以让请求进行等待,不需要直接拒绝请求

原文地址 [https://www.jianshu.com/p/d60eefc3507a](https://www.jianshu.com/p/d60eefc3507a)

 

你可能感兴趣的:(限流,算法,java)