SpringCloud | Gateway(3)-网关限流

1,976 阅读2分钟

环境 SpringCloud:Finchley.RELEASE SpringBoot:2.0.0.RELEASE JDK:1.8

1. 网关限流

1.1 限流算法

1.1.1 计数器

计数器算法是通过维护一个单位时间内的计数器,每次请求计数器+1,当单位时间累加的计数器超过设置的阈值,则之后的请求全部拒绝,直到单位时间过去,把计数器清0

缺点:不能平滑的限流,如1分钟限制请求50次,在10秒时达到请求上线,则从11-60之间的所有请求全部拒绝

1.1.2 漏桶算法

漏桶算法可以很好的控制容容量池的大小,从而防止流量暴增。漏桶可以看成一个服务队列,如果漏桶溢出,则请求会被丢弃。漏桶算法可以控制流量输出速率,实现流量整形,平滑流量突发情况。 漏桶算法有2个变量需要控制,一个是桶的大小,一个是流量输出速率

1.1.3 令牌桶算法

令牌桶算法是对漏桶算法的改进,存在一个桶用来存放固定数量的令牌。算法中存在一种机制,以一定的速率给桶中放入令牌,每次请求需要先获取令牌,只有获取到令牌的请求可以继续请求微服务,否则等待令牌或者丢弃请求。放令牌的动作是持续进行的,如果令牌桶中令牌达到上限,就会丢弃令牌。

1.2 基于SpringCloud gateway的过滤器限流

Springcloud gateway官方提供了基于令牌桶的限流算法,基于内部的过滤器工厂RequestRateLimiterGatewayFilterFactory实现。在过滤器工厂内部是通过Redis和lua脚本结合的方式进行流量控制

  1. 导入redis的依赖、安装redis
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        </dependency>
  1. application.yml中的限流配置和redis配置
spring:
  application:
    name: microservice-gateway
  redis:
    host: localhost
    port: 6379
    database: 0
  cloud:
    gateway:
      routes: #设置路由:路由id、路由打微服务的uri、断言
      - id: microservice-provider #路由ID,全局唯一
#        uri: http://127.0.0.1:8001 #目标微服务的请求地址和端口
        uri: lb://microservice-provider  # lb://微服务名 根据微服务名称从注册中心获取地址
        predicates:
        - Path=/product/**  #路由条件,采用path路由规则
        filters:  # 实现重写转发路径: http://localhost:6101/product/provider/list --> http://localhost:6101/provider/list
        - RewritePath=/product/(?<segment>.*), /$\{segment}
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 1 #令牌桶每秒放入速率
            redis-rate-limiter.burstCapacity: 3  #令牌桶的上限
#            key-resolver: "#{@pathKeyResolver}"  #基于请求路径的限流解析
            key-resolver: "#{@userKeyResolver}" #基于请求参数的限流解析
  1. 设置KeyResovlver
@Configuration
@Log4j2
public class KeyResolverConfiguration {

    /**
     * 基于请求路径的限流规则
     */
    @Bean
    public KeyResolver pathKeyResolver() {
        return new KeyResolver() {
            @Override
            public Mono<String> resolve(ServerWebExchange exchange) {
                return Mono.just(exchange.getRequest().getPath().toString());
            }
        };
    }


    /**
     *  基于请求参数限流
     */
    @Bean
    public KeyResolver userKeyResolver() {
        return  exchange -> Mono.just(
            exchange.getRequest().getQueryParams().getFirst("userId")
        );
    }
}

代码示例