Spring Cloud series _34 Gateway current limit

I won’t go into details about the concept and model of current limiting , and there is a detailed overview in the article "Spring Cloud Series_27 Zuul and Hystrix Integration, Fuse, Current Limiting"

URL current limit based on token bucket algorithm

Limit flow based on URL:

Spring Cloud Gateway officially provides the RequestRateLimiterGatewayFilterFactory filter factory, which uses Redis and Lua scripts to implement the token bucket method. The specific implementation logic is in the RequestRateLimiterGatewayFilterFactory class, and the Lua script is in the file below.

  • Introduce dependencies
        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>        </dependency>         <dependency>            <groupId>org.apache.commons</groupId>            <artifactId>commons-pool2</artifactId>        </dependency>

There should be no difference between spring-boot-starter-data-redis-reactive and spring-boot-starter-data-redis I checked by myself

  • Configure
spring:    application:        name: service-gateway-server    redis:        timeout: 10000 #连接超时时间        host: 123.60.8.97        port: 6379        database: 0 #选择哪个库 默认0        lettuce:            pool:                max-active: 1024 #最大连接数,默认8                max-wait: 10000 #最大链接阻塞等接待时间,单位毫秒,默认是-1                max-idle: 200 #最大空闲连接,默认是8                min-idle: 5 #最大空闲连接,默认是0    cloud:        gateway:            #路由规则            routes:                -   id: service-provider-gateway #路由ID,唯一                    uri: lb://service-provider-gateway # lb:// 根据服务名称从注册中心获取服务请求地址                    predicates:                 # 断言(判断条件)                        - Path=/**   # 匹配对应的URI的请求,将匹配到的请求追加在目标URI之后                    filters:                        # 限流过滤器                        - name: RequestRateLimiter                          args:                              redis-rate-limiter:                                  replenishRate: 1 # 令牌桶每秒填充速率                                  burstCapacity: 2 #令牌桶总量                                  key-resolver: '#{@pathKeyResolver}' #使用SpEl表达式按名称引用Bean

From top to bottom, add the configuration of Redis, because the token is stored in Redis, the route is set to obtain the request address according to the service name of the Eureka registry, all paths are judged, and the flow-limiting filter RequestRateLimiter is set. , Set to generate a token every second, the total number of tokens is 2 (set a small point to facilitate testing), here

The key-resolver is the current limiting rule that is quoted, #{@ is followed by the ID of the injected object}, and the method name injected through the @bean annotation is used as the ID of the injected object, which is the following object

KeyResolverConfig.java

package gateway.config; import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.server.ServerWebExchange;import reactor.core.publisher.Mono; /** * 描述 限流规则配置类 * * @author Oliver * @version 1.0 * @date 2021/06/03 13:53:18 */@Configurationpublic class KeyResolverConfig {     /**     * 限流规则     * @return org.springframework.cloud.gateway.filter.ratelimit.KeyResolver     * @date: 2021-06-03 13:54     * @author Oliver    **/    @Bean    public KeyResolver pathKeyResolver(){        /* 匿名内部类写法        return new KeyResolver() {            @Override            public Mono<String> resolve(ServerWebExchange exchange) {                return Mono.just(exchange.getRequest().getPath().toString());            }        };*/        //JDK1.8以上写法        return exchange -> Mono.just(exchange.getRequest().getURI().getPath());    }}

For convenience I put

GatewayRoutesConfig.java

This custom gateway configuration will not be injected as a component first

At this time, the URL-based current-limiting function has been configured. The flow-limiting process is to request a token from the token bucket first, and then the token can be accessed normally. Now the rate of token generation is one per second. The amount is 2, if we use a fixed slower rate to access (such as once a second), it is no problem, and the continuous access will prompt 429 in an instant.

Normal access effect:

Failure effect

Open Redis and look at it and found that it is indeed the current limit through Url

Parameter current limit

As the name suggests, it is to limit the current according to the parameters you configure. If the request with the same parameter cannot get the token, the current will be limited. The actual operation is to modify the current limit rule and reference the new Bean in the configuration.

//    @Bean    public KeyResolver pathKeyResolver(){        /* 匿名内部类写法        return new KeyResolver() {            @Override            public Mono<String> resolve(ServerWebExchange exchange) {                return Mono.just(exchange.getRequest().getPath().toString());            }        };*/        //JDK1.8以上写法        return exchange -> Mono.just(exchange.getRequest().getURI().getPath());    }     /**     * 限流规则 根据参数限流     * @return org.springframework.cloud.gateway.filter.ratelimit.KeyResolver     * @date: 2021-06-03 13:54     * @author Oliver     **/    @Bean    public KeyResolver parameterKeyResolver(){        return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getQueryParams().getFirst("id")));    }

Note here that the KeyResolver class can only have one Bean at the same time. If there are two, an error will be reported, so I commented out the previous URL-limiting Bean, and this ID parameter is required at this time, if the request does not have this The parameter will report an error. Introduce some rules in the configuration

key-resolver:'#{@parameterKeyResolver}' #Use SpEl expression to refer to Bean by name

After restarting the service, visit http://localhost:8082/provider/single?token=1&id=1 and the  effect is the same. Look at Redis

It is found that the current limit is indeed carried out according to id = 1. If the id is changed to 2, the current limit will be carried out by 2.

Limit flow based on IP

Old rules, go directly to the code

/**     * 限流规则 根据IP限流     * @return org.springframework.cloud.gateway.filter.ratelimit.KeyResolver     * @date: 2021-06-03 13:54     * @author Oliver     **/    @Bean    public KeyResolver ipKeyResolver(){        return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getHostName());    }

The test effect is the same, check Redis