前言:本文基于您已有基础的可运行的微服务系统,使用了Sping Cloud Alibaba,Gateway,Nacos等;目标实现网关流控类型的限流。

顾名思义限流用于在高并发场景下限制请求流量的进入,保护系统不被冲垮。阿里巴巴的开源sentinel可以通过设置不同种类规则实现对不同的资源的保护。

  • 资源:可以是任何东西;服务,方法,代码...
  • 规则:流控规则、熔断降级规则、系统保护规则、热点规则、网关API分组规则、网关流控规则

本文使用的各版本对应关系如下(官方链接:版本对应关系)

<spring.boot>2.6.7</spring.boot>
<spring-cloud>2021.0.2</spring-cloud>
<spring-cloud-alibaba>2021.0.4.0</spring-cloud-alibaba>

本文目标

  • 微服务整合sentinel
  • 使用sentinel客户端生成网关限流规则,并持久化到nacos中
  • 规则生效,产生限流效果

三步走战略


1.整合sentinel

1.1.服务端整合

1.1.1.引入pom

<!--网关组件-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<!--sentinel限流-->
<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<!-- SpringCloud Ailibaba Sentinel Gateway -->
<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

<!-- 通过nacos持久化流控规则 -->
<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

配置Sentinel Starter,必须有spring-cloud-alibaba-sentinel-gateway,spring-cloud-starter-gateway 依赖来让 spring-cloud-alibaba-sentinel-gateway 模块里的 Spring Cloud Gateway 自动化配置类生效。

避坑点1:通过Spring Cloud Alibaba接入sentinel需要将spring.cloud.sentinel.filter.enabled 配置项置为 false(网关流控默认粒度为route和自定义API分组维度,不支持URL粒度)

避坑点2:通过Spring Cloud Alibaba Sentinel 数据源模块,网关流控规则数据源类型是 gw-flow而不是flow

1.1.2.编写规则配置文件

在gatewaymodule中新建application-sentinel.yaml文件

配置规则

spring:
  cloud:
    sentinel:
      enabled: true
      datasource:
        ds1:
          nacos:
            server-addr: ${spring.cloud.nacos.config.server-addr}
            namespace: ${spring.cloud.nacos.config.namespace}
            data-id: ${spring.application.name}-gateway-flow-rules
            group-Id: SENTINEL_GROUP
            rule-type: gw-flow
            data-type: json
        ds2:
          nacos:
            server-addr: ${spring.cloud.nacos.config.server-addr}
            namespace: ${spring.cloud.nacos.config.namespace}
            data-id: ${spring.application.name}-gateway-api-rules
            group-Id: SENTINEL_GROUP
            rule-type: gw-api-group
            data-type: json
          ds3:
            nacos:
              server-addr: ${spring.cloud.nacos.config.server-addr}
              namespace: ${spring.cloud.nacos.config.namespace}
              data-id: ${spring.application.name}-degrade-rules
              group-Id: SENTINEL_GROUP
              rule-type: degrade
              data-type: json
          ds4:
            nacos:
              server-addr: ${spring.cloud.nacos.config.server-addr}
              namespace: ${spring.cloud.nacos.config.namespace}
              data-id: ${spring.application.name}-system-rules
              group-Id: SENTINEL_GROUP
              rule-type: system
              data-type: json
      log:
        dir: /home/omo/sentinel/logs
        # 启用向sentinel发送心跳
      eager: true
      scg:
        fallback:
          response-status: 429
          mode: response
          response-body: '{"code": 429,"message": "前方拥堵,请稍后再试!"}'

1.sentinel dashboard默认会以spring.application.name开头生成规则,ds1、ds2为本次测试的类型

2.data-type为读取数据类型,此处设置为json

3.最后的fallback配置了被限流后的自定义响应

1.1.3.配置通信端口

服务和sentinel dashboard之间通信端口配置

spring:
  cloud:
    sentinel:
      transport:
        # sentinel控制台地址
        dashboard: localhost:8081
        # 跟sentinel控制台交流的端口,随意指定一个未使用的端口即可,默认是8719
        port: 8719
        # Get heartbeat client local ip
        clientIp: 127.0.0.1

1.2.sentinel dashboard整合

Sentinel 1.6.3 引入了网关流控控制台的支持,可以直接在 Sentinel 控制台上查看 API Gateway 实时的 route 和自定义 API 分组监控,管理网关规则和 API 分组配置

首先需要下载控制台工程代码,自行修改编译。也可以使用我改造后的工程,开箱即用:sentinel-dashboard-1.8.6,改造后的工程支持多种规则配置管理、规则推送(推送到nacos)

启动前配置nacos地址和命名空间(application.properties)

启动参数配置(IDEA)

-Dserver.port=8081 -Dcsp.sentinel.dashboard.server=localhost:8081 -Dproject.name=sentinel-dashboard

启动后效果

2.push模式规则持久化

push模式流程

(下载sentinel dashboard官方版本时需要自行实现,懒人可直接使用上面我提供的改造后版本)

下面列出核心修改点

2.1.修改nacosConfig类

@Bean
public ConfigService nacosConfigService() throws Exception {
    Properties properties = new Properties();
    //nacos地址
    properties.put(PropertyKeyConst.SERVER_ADDR, nacosAddr);
    //namespace为空即为public
    properties.put(PropertyKeyConst.NAMESPACE, namespace);
    return ConfigFactory.createConfigService(properties);
}

以及对应规则类型的provider和publisher,以GatewayFlowRule举例:

2.2.修改发布规则实现(publisher)

@Component("gatewayFlowRuleNacosPublisher")
public class GatewayFlowRuleNacosPublisher implements DynamicRulePublisher<List<GatewayFlowRuleEntity>> {

    @Autowired
    private ConfigService configService;

    @Autowired
    private Converter<List<GatewayFlowRuleEntity>, String> converter;

    @Override
    public void publish(String app, List<GatewayFlowRuleEntity> rules) throws Exception {
        AssertUtil.notEmpty(app, "app name cannot be empty");
        if (rules == null) {
            return;
        }
        configService.publishConfig(app + NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,
                NacosConfigUtil.GROUP_ID, converter.convert(rules));
    }
}

2.3.修改获取规则实现(provider)

@Component("gatewayFlowRuleNacosProvider")
public class GatewayFlowRuleNacosProvider implements DynamicRuleProvider<List<GatewayFlowRuleEntity>> {
    @Autowired
    private ConfigService configService;

    @Autowired
    private Converter<String, List<GatewayFlowRuleEntity>> converter;

    @Override
    public List<GatewayFlowRuleEntity> getRules(String appName) throws Exception {
        String rules = configService.getConfig(appName + NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,
                NacosConfigUtil.GROUP_ID, 3000);
        if (StringUtil.isEmpty(rules)) {
            return new ArrayList<>();
        }
        return converter.convert(rules);
    }
}

2.4.修改对应接口

(GatewayFlowRuleController中)

引入

@Autowired
@Qualifier("gatewayFlowRuleNacosProvider")
private DynamicRuleProvider<List<GatewayFlowRuleEntity>> ruleProvider;

@Autowired
@Qualifier("gatewayFlowRuleNacosPublisher")
private DynamicRulePublisher<List<GatewayFlowRuleEntity>> rulePublisher;

再修改增删改查方法中的实现,具体细节参考:sentinel-dashboard-1.8.6

3.配置规则,测试限流效果

3.1 启动sentinel dashboard

启动步骤见上面阐述

3.2 配置网关限流规则

3.2.1 配置Route类型规则

针对user服务(为你的网关路由配置中的id)配置了QPS=5,流控方式为快速失败的规则

到nacos后台查看规则详情,已同步到nacos

同样在nacos中修改,dashboard也会同步更新,不再演示。 (规则属性含义参考:限流字段)

3.2.2.配置API分组类型规则

先配置API分组

再配置规则(下拉选择刚才配置的分组,同样设置QPS=5)

3.3 测试限流效果

3.3.1.Route类型限流

设置测试用例 设置循环10次

测试结果5次成功5次失败,符合预期,大功告成!

3.3.2.API分组限流

可以看到测试报告中对/auth/oms/** 的路径匹配到了且限流可以生效

4.扩展

  • 网关流控原理,详见官网

  • 在使用SpringCloud Gateway和SpringCloud Sentinel时,官方不支持针对4xx,5xx响应码做异常统计熔断,可以自行实现,可参考issue1842 issue2537

Java架构师
176 声望61 粉丝