Implementation of Spring Cloud Gateway and Spring Cloud Alibaba Sentinel Gateway Current Limiting

Earlier, we know that Spring Cloud Gateway implements a RequestRateLimiter filter, which will perform a current limiting filter on all requests to the current gateway. If the current is limited, it will respond to Http-429-Too Many Requests by default. . RequestRateLimiterGatewayFilterFactory provides RedisRateLimiter's current limiting implementation by default. It uses the token bucket algorithm to implement the current limiting function. As follows, we can configure the filter—RequestRateLimiter in the Spring Cloud Gateway configuration:

spring:
  cloud:
    gateway:
      routes:
        - id: redis_limiter
          uri: https://example.org
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
server:
  port: 8081

The redis-rate-Limiter has two attributes, namely replenishRate, which means the speed at which the tokens in the token bucket are filled, which means the number of requests that can be executed per second, and burstCapacity means the capacity of the token bucket, which means the maximum number of requests executed by the user per second. . The current limit of redis is based on Stripe, and the following dependencies need to be added:

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

We can implement the KeyResolver interface to set the key of the current limit request, and specify which factors in the current request to limit the current. The following code is the IP requested by our team to limit the current:

public class IpAddressKeyResolver implements KeyResolver {
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    }
}

 The default implementation of KeyResolver is PrincipalNameKeyResolver, which retrieves the Principal from ServerWebExchange and calls the Principal.getName method. By default, if the KeyResolver does not obtain the key, the request will be rejected. We can adjust the parameters of the current limit filter to denyEmptyKey and emptyKeyStatus respectively. The following is the configuration of IP current limiting:

spring:
  cloud:
    gateway:
      routes:
        - id: redis_limiter
          uri: https://example.org
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                denyEmptyKey: true
                emptyKeyStatus: SERVICE_UNAVAILABLE
                keyResolver: '#{@ipAddressKeyResolver}'
server:
  port: 8081

 When we call the interface, redis will generate two keys respectively request_rater_limiter.{ip}.timestamp and request_rater_limiter.{ip}.tokens. Spring Cloud Gateway only implements the RateLimiter current limiting mode based on Redis. We can customize xianliuq by implementing AbstractRateLimiter and specify the current limiter by configuration:

rateLimiter:  #{@rateLimiterName}

Spring Cloud Alibaba Sentinel provides support for Spring Cloud Gateway from version 1.6. It supports the current limit of two resource dimensions, namely Route dimension and custom API dimension. You can use the provided API to customize API grouping, and then limit these groups. flow. We need to introduce the Sentinel-Adapter dependency package:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
    <version>1.7.1</version>
</dependency>

When we introduced Sentinel earlier, we used FlowRule to provide flow restriction rules, while in Spring Cloud Gateway, Sentinel used GatewayFlowRule as flow restriction rules. The following is a simple example:

private void initGatewayRules() {
    Set<GatewayFlowRule> gatewayFlowRules = new HashSet<GatewayFlowRule>();
    GatewayFlowRule rule = new GatewayFlowRule().setCount(5).setIntervalSec(1).setResource("gateway-sentinel-limiter");
    gatewayFlowRules.add(rule);
    GatewayRuleManager.loadRules(gatewayFlowRules);
}

Similar to FlowRule, GatewayFlowRule provides the following properties: Here we directly copy and comment part of the code for setting properties in the source code. The code is as follows:

//设置资源名称,可以是网关配置中的route名称或者用户自定义的API分组
public GatewayFlowRule setResource(java.lang.String resource) {  }
//资源模型,限流针对API Gateway的route还是用户在sentinel定义的API分组
public GatewayFlowRule setResourceMode(int resourceMode) {  }
// 限流指标维度,同FlowRule的grade字段
public GatewayFlowRule setGrade(int grade) { }
//同FlowRule的controlBehavior字段,支持快速失败和匀速排队
public GatewayFlowRule setControlBehavior(int controlBehavior) { }
//限流阈值
public GatewayFlowRule setCount(double count) {  }
//统计时间窗口,单位为秒,默认是1秒
public GatewayFlowRule setIntervalSec(long intervalSec) { }
//应对突发请求时额外允许的请求数目
public GatewayFlowRule setBurst(int burst) { }
//匀速排队下最长排队时间
public GatewayFlowRule setMaxQueueingTimeoutMs(int maxQueueingTimeoutMs) { }
//参数限流配置,若不提供,则代表不针对参数进行限流。从请求中提取参数的策略,下面的类为GatewayParamFlowItem提供的属性
public GatewayFlowRule setParamItem(GatewayParamFlowItem paramItem) { }
public class GatewayParamFlowItem {
    private java.lang.Integer index;
    //解析策略:目前支持IP,HOST,任意Header和任意URL参数四种模式,
    private int parseStrategy;
    //为Header和URL策略时的Header 名称或者URL参数名称
    private java.lang.String fieldName;
    //下面的两个目前没有实现,后续可能会实现
    private java.lang.String pattern;
    private int matchStrategy;
}

Sentinel's support for Spring Cloud Gateway current limiting is actually a global filter. We can inject the global filter into the container, and then the global filter will take effect. The following is the configuration used by Sentinel in Spring Cloud Gateway:

Configuration
public class SentinelRateLimiterConfiguation {
    private final List<ViewResolver> viewResolverList;
    private final ServerCodecConfigurer serverCodecConfigurer;
    //注入视图解析器
    public SentinelRateLimiterConfiguation(ObjectProvider<List<ViewResolver>> viewResolverList, ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolverList = viewResolverList.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }
    //注入Sentinel全局过滤器SentinelGatewayFilter
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
    //注入限流异常处理器
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        return new SentinelGatewayBlockExceptionHandler(viewResolverList, serverCodecConfigurer);
    }
    //初始化限流规则
    @PostConstruct
    public void initRules() {
        initGatewayRules();
    }

    private void initGatewayRules() {
        Set<GatewayFlowRule> gatewayFlowRules = new HashSet<GatewayFlowRule>();
        GatewayFlowRule rule = new GatewayFlowRule().setCount(5).setIntervalSec(1).setResource("gateway-sentinel-limiter");
        gatewayFlowRules.add(rule);
        GatewayRuleManager.loadRules(gatewayFlowRules);
    }
}

After configuring Sentinel, we need to configure the relevant configuration of the Spring Cloud Gateway gateway, the configuration is as follows:

spring:
  cloud:
    gateway:
      routes:
        - id: gateway-sentinel-limiter
          uri: https://example.org
          predicates:
            -path=/sentinel/rate

As we said before, in addition to using route current limiting, we can also customize the grouping for current limiting. In fact, let multiple routes use one current limiting rule. To join we need the following two routes to use a current limiting rule:

spring:
  cloud:
    gateway:
      routes:
        - id: exmaple-sentinel-limiter
          uri: https://example.org
          predicates:
            -path=/sentinel/rate
        - id: example1-sentinel-limiter
            uri: https://example1.org
            predicates:
              -path=/sentinel1/rate

Next, we can configure the above two routes to the same group, and then use the same current limiting rule. The following code defines the above two routes into one group:

private void initCustomizedApis() {
    ApiDefinition api = new ApiDefinition("customized-apis");
    Set<ApiPredicateItem> apiPredicateItems = new HashSet<ApiPredicateItem>();
    apiPredicateItems.add(new ApiPathPredicateItem().setPattern("/sentinel/rate"));
    apiPredicateItems.add(new ApiPathPredicateItem().setPattern("/sentinel1/rate").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_REGEX));
    api.setPredicateItems(apiPredicateItems);
}

After defining the grouping, when we set the resource when defining the current limiting rules, that is, when setResource(), the resource can be set to customized-apis. code show as below:

private void initGatewayRules() {
        Set<GatewayFlowRule> gatewayFlowRules = new HashSet<GatewayFlowRule>();
        GatewayFlowRule rule = new GatewayFlowRule().setCount(5).setIntervalSec(1).setResource("customized-apis").setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME);
        gatewayFlowRules.add(rule);
        GatewayRuleManager.loadRules(gatewayFlowRules);
    }

 

Guess you like

Origin blog.csdn.net/wk19920726/article/details/108568218