spring cloud gateway整合sentinel + nacos 实现网关限流和持久化动态配置

Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。
从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId
自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

Sentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common 模块,此模块中包含网关限流的规则和自定义 API 的实体和管理逻辑:

GatewayFlowRule :网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同
route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的
限流。
ApiDefinition :用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以
定义一个 API 叫 customized_api ,请求 path 模式为 /api/v8/**, /api/v5/ 的匹配路径都归到 customized_api 这个 API
分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。

这篇文章主要介绍了spring cloud gateway整合sentinel实现网关限流,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下,Spring Cloud Gateway工程的搭建和Nacos的搭建不在这里讲述。

说明: sentinel可以作为各微服务的限流(点击查看),也可以作为gateway网关的限流组件。 spring cloud gateway有限流功能,但此处用sentinel来作为替待。

说明:sentinel流控可以放在gateway网关端,也可以放在各微服务端。

1、sentinel_dashboard的引入

下载sentinel-dashboard-1.6.3.jar
由于dashboard是springboot的项目,在CMD模式下使用命令
java -Dserver.port=8090 -Dcsp.sentinel.app.type=1 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar F:\workspace\sentinel\sentinel-dashboard-1.6.3.jar

-Dcsp.sentinel.app.type=1 表示 Sentinel 网关类型

浏览器访问地址:http://localhost:8090/#/login
spring cloud gateway整合sentinel + nacos 实现网关限流和持久化动态配置_第1张图片
登录后看到菜单有 “API管理“ 表示成功启动了Sentinel网关类型的控制台
spring cloud gateway整合sentinel + nacos 实现网关限流和持久化动态配置_第2张图片
2、Spring cloud gateway服务引入Nacos,Sentinel 依赖包(注意版本)

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
                    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
            <version>1.6.3</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.7.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
            <version>1.8.0</version>
        </dependency>

Spring cloud gateway服务添加Nacos 相关配置

spring:
  application:
    # 应用名称
    name: gateway-master
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      httpclient:
        pool:
          max-idle-time: 10000
      discovery:
        locator:
          enabled: true

Spring cloud gateway服务增加Sentinel配置类

@Configuration
public class GatewaySentinelConfiguration {
    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

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


    /**
     * 配置SentinelGatewayBlockExceptionHandler,限流后异常处理
     *
     * @return
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    // 自定义限流异常页面
    @PostConstruct
    public void initBlockHandlers() {
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                Map result = new HashMap();
                result.put("Suc","false");
                result.put("ErrCode",0);
                result.put("Info","接口被限流了");
                return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromObject(result));
            }
        };
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }

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

3、进入nacos控制台-配置列表添加配置

dataId: sentinel-gateway-rules
groupId: sentinel

[
    {
        "resource": "api-v8-order1",
        "resourceMode": 0,
        "count": 1,
        "intervalSec": 10
    },
    {
        "resource": "customized_api",
        "resourceMode": 1,
        "pattern": "/api/v5/**",
        "count": 1,
        "intervalSec": 10
    }
]

resource: 资源名称
resourceMode: 资源模式 0-路由ID模式 1-自定义API模式
count:限流阈值
intervalSec: 统计时间窗口,单位是秒,默认是 1 秒
pattern: 自定义API模式下的限流资源路径
spring cloud gateway整合sentinel + nacos 实现网关限流和持久化动态配置_第3张图片
Spring cloud gateway服务添加Nacos配置监听类,服务启动自动加载Nacos已有的限流配置

@Component
public class DynamicFlowRulesServiceImplByNacos implements CommandLineRunner {
    protected static final Logger log = LoggerFactory.getLogger(DynamicFlowRulesServiceImplByNacos.class);
    @Autowired
    private NacosGatewayProperties nacosGatewayProperties;
    private ConfigService configService;


    /**
     * 监听Nacos Server下发的动态配置
     */
    public void dynamicByNacosListener() {
        if (configService == null) {
            try {
                configService = NacosFactory.createConfigService(nacosGatewayProperties.getAddress());
            } catch (NacosException e) {
                e.printStackTrace();
            }
        }
        sentinelConfigByNacosListener();
    }

    /**
     * 网关动态配置基础信息
     */
    public void sentinelConfigByNacosListener() {
        try {
            String dataId = "sentinel-gateway-rules";
            String groupId = "sentinel";
            String fristConfigInfo = configService.getConfigAndSignListener(dataId, groupId, 5000, new Listener() {
                @Override
                public void receiveConfigInfo(String configInfo) {

                    addListenerByConfig(dataId, groupId, configInfo);
                }

                @Override
                public Executor getExecutor() {
                    return null;
                }
            });

            addListenerByConfig(dataId, groupId, fristConfigInfo);
        } catch (NacosException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     */

    public void addListenerByConfig(String dataId, String groupId, String configInfo) {
        log.info("DataId:" + dataId + ",GroupId:" + groupId + ",监听器获取的nacos-sentinel流控配置信息:" + configInfo);
        //配置删除或不存在
        if (configInfo == null) {
            initDefultGatewaySentinelRules();
            return;
        }
        List<GatewaySentinelConfig> gatewaySentinelConfigs = null;
        try {
            gatewaySentinelConfigs = new Gson().fromJson(configInfo, new TypeToken<List<GatewaySentinelConfig>>() {
            }.getType());
        } catch (JsonSyntaxException e) {
            log.error("JsonSyntaxException", e, e.getMessage());
        }
        if (gatewaySentinelConfigs == null || gatewaySentinelConfigs.size() == 0) {
            return;
        }
        //加载流控规则
        initGatewaySentinelRules(gatewaySentinelConfigs);
    }

    public void initGatewaySentinelRules(List<GatewaySentinelConfig> gatewaySentinelConfigs) {
        Set<GatewayFlowRule> rules = new HashSet<>();
        Set<ApiDefinition> definitions = new HashSet<>();
        for (GatewaySentinelConfig sentinelConfig : gatewaySentinelConfigs) {
            rules.add(new GatewayFlowRule(sentinelConfig.resource)
                    .setResourceMode(sentinelConfig.resourceMode)
                    .setCount(sentinelConfig.count)  // 限流阈值
                    .setIntervalSec(sentinelConfig.intervalSec)  // 统计时间窗口,单位是秒,默认是 1);
            if (sentinelConfig.resourceMode == 1) {  //自定义API模式
                ApiDefinition api1 = new ApiDefinition(sentinelConfig.resource).setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    if (sentinelConfig.pattern.contains("**")) {
                        //前缀匹配
                        add(new ApiPathPredicateItem().setPattern(sentinelConfig.pattern).setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                    }
                }});
                definitions.add(api1);
            }
        }
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
        GatewayRuleManager.loadRules(rules);
    }

    //配置删除,初始化一个默认规则
    public void initDefultGatewaySentinelRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        rules.add(new GatewayFlowRule("no-rule")
                .setResourceMode(0)
                .setCount(10000000)  // 限流阈值
                .setIntervalSec(1));  // 统计时间窗口,单位是秒,默认是 1 秒
        GatewayRuleManager.loadRules(rules);
    }


    @Override
    public void run(String... args) throws Exception {
        dynamicByNacosListener();
    }
}

4、启动Spring cloud gateway服务
增加系统启动参数:-Dcsp.sentinel.app.type=1 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=gateway-sentinel

-Dcsp.sentinel.app.type=1 Sentinel 网关类型
-Dcsp.sentinel.dashboard.server=localhost:8090 限流控制服务地址
-Dproject.name=gateway-sentinel 注册到限流服务控制的项目名称

spring cloud gateway整合sentinel + nacos 实现网关限流和持久化动态配置_第4张图片
5、连续访问接口地址验证限流

出现以下信息表示限流成功
spring cloud gateway整合sentinel + nacos 实现网关限流和持久化动态配置_第5张图片
查看Sentinel控制台流控规则
spring cloud gateway整合sentinel + nacos 实现网关限流和持久化动态配置_第6张图片

spring cloud gateway整合sentinel + nacos 实现网关限流和持久化动态配置_第7张图片
6、Nacos配置中心修改限流规则验证动态加载配置
spring cloud gateway整合sentinel + nacos 实现网关限流和持久化动态配置_第8张图片
idea控制台会输出监听到的新配置
spring cloud gateway整合sentinel + nacos 实现网关限流和持久化动态配置_第9张图片
Sentinel控制台查看规则是否自动更新
spring cloud gateway整合sentinel + nacos 实现网关限流和持久化动态配置_第10张图片
以上就是本文的全部内容,希望对大家的学习有所帮助。

你可能感兴趣的:(spring,boot,java,java,spring,cloud,gateway)