spring cloud gateway集成sentinel实现网关限流全局处理

官网地址 https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81

Sentinel 1.6.0发布了Sentinel API网关适配器通用模块,此模块中包含网关限流的规则和自定义API的实体和管理逻辑:
  • GatewayFlowRule:网关限流规则,针对API Gateway的场景定制的限流规则,可以针对不同的路由或自定义的API分组进行限流,支持针对请求中的参数,标头,来源IP等进行定制化的限流。
  • ApiDefinition:用户自定义的API定义分组,可以看做是一些URL匹配的组合。就像我们可以定义一个API一样my_api,请求路径模式为/foo/**和/baz/**的都归到my_api这个API分组。限流的时候可以针对这个自定义的API分组维度进行限流。
其中网关限流规则GatewayFlowRule的细分解释如下:
  • resource:资源名称,可以是网关中的路线名称或用户自定义的API分组名称。
  • resourceMode:规则是针对API网关的路由(RESOURCE_MODE_ROUTE_ID)还是用户在Sentinel中定义的API分组(RESOURCE_MODE_CUSTOM_API_NAME),而是路由。
  • grade:限流指标维度,同限流规则的grade细分。
  • count:限流阈值
  • intervalSec:统计时间窗口,单位是秒,至少是1秒。
  • controlBehavior:流量整形的控制效果,同限流规则的controlBehavior细分,目前支持快速失败和匀速排队两种模式,而是是快速失败。
  • burst:应对突发请求时额外允许的请求数量。
  • maxQueueingTimeoutMs:匀速排队模式下的最大排队时间,单位是几分钟,仅在匀速排队模式下生效。
  • paramItem:参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。
    • parseStrategy:从请求中提取参数的策略,当前支持提取源IP(PARAM_PARSE_STRATEGY_CLIENT_IP),主机(PARAM_PARSE_STRATEGY_HOST),任意头(PARAM_PARSE_STRATEGY_HEADER)和任意URL参数(PARAM_PARSE_STRATEGY_URL_PARAM)模式。
    • fieldName:如果提取策略选择Header模式或URL参数模式,则需要指定对应的header名称或URL参数名。
    • pattern:参数值的匹配模式,只有匹配该模式的请求属性值会重新统计和流控;若为空则统计该请求属性的所有值。(1.6.2版本开始支持)
    • matchStrategy:参数值的匹配策略,当前支持精确匹配(PARAM_MATCH_STRATEGY_EXACT),子串匹配(PARAM_MATCH_STRATEGY_CONTAINS)和正则匹配(PARAM_MATCH_STRATEGY_REGEX)。(1.6.2版本开始支持)
用户可以通过GatewayRuleManager.loadRules(rules)手动加载网关规则,或通过GatewayRuleManager.register2Property(property)注册动态规则源动态推送(推荐方式)
 
SpringCloudGateway
引入Maven依赖
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
注入对应的 SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例
sentinel提供了两种方式用来设置资源
1.通过配置文件进行路由设置
server:
  port: 8085


spring:
  main:
    allow-bean-definition-overriding: true
  application:
    name: live-gateway
  profiles:
    active: loc
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      enabled: true
      discovery:
        locator:
          lower-case-service-id: true
      routes:
#        会被标识为 Sentinel 的资源
        - id:cloud_route
          uri: lb://spring/cloud/test
          predicates:
            - Path=/spring/cloud/test/**

网关设置路由:

 对应的服务:

2.在代码中进行设置

import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.live.gateway.handler.GatewayHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;


import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


/**
* @author wjc
* @description
* @date 2020/10/9
*/
@Configuration
public class GatewayConfig {


    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;


    public GatewayConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                         ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }


    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }


    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }


    @PostConstruct
    public void doInit() {
        initCustomizedApis();
        initGatewayRules();
        //自定义处理被限流的请求
        GatewayCallbackManager.setBlockHandler(new GatewayHandler());
    }


    //详细配置参考官方文档
    private void initCustomizedApis() {
        Set<ApiDefinition> definitions = new HashSet<>();
        ApiDefinition api1 = new ApiDefinition("some_customized_api")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    add(new ApiPathPredicateItem().setPattern("/spring/cloud/test/**")
                            .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                }});
        definitions.add(api1);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }


    private void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();


        rules.add(new GatewayFlowRule("some_customized_api")
                .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
                .setCount(1)
                .setIntervalSec(1)
        );
        GatewayRuleManager.loadRules(rules);
    }


}
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;


/**
* @author wjc
* @description
* @date 2020/10/9
*/
public class GatewayHandler implements BlockRequestHandler {


    private static final String DEFAULT_BLOCK_MSG_PREFIX = "Blocked by Sentinel: ";


    @Override
    public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
        ServerHttpRequest request = serverWebExchange.getRequest();
        System.out.println(request.getPath());
        return ServerResponse.status(200)
                .contentType(MediaType.APPLICATION_JSON)
//                .body(BodyInserters.fromValue(buildErrorResult(throwable)));
                .body(BodyInserters.fromValue(buildErrorResult(request.getPath().value())));
    }


    private ErrorResult buildErrorResult(Throwable ex) {
//        return new ErrorResult(200, DEFAULT_BLOCK_MSG_PREFIX + ex.getClass().getSimpleName());
        return new ErrorResult(500, "限流");
    }


    private ErrorResult buildErrorResult(String path) {
        if(path.equals("/spring/cloud/test/block/handler")){
            return new ErrorResult(200, "hhahahhahah限流");
        }
        return new ErrorResult(500, "限流");
    }


    private static class ErrorResult {
        private final int code;
        private final String message;


        ErrorResult(int code, String message) {
            this.code = code;
            this.message = message;
        }


        public int getCode() {
            return code;
        }


        public String getMessage() {
            return message;
        }
    }
}

通过网关请求接口

达到阈值限流

 

原文地址:https://www.cnblogs.com/gqymy/p/13794583.html