SpringCloud简单工程样例以及一些思考

696 阅读10分钟

1. 项目创建

先创建一个项目,删除无用的文件夹(比如src),剩下pom文件。
创建两个Module,一个作为消费者,一个作为生产者。 image.png

在父项目中的pom.xml中设置打包类型:

<packaging>pom</packaging>

表示则此模块是一个标准的Maven工程模块,只用于管理子模块和依赖关系,不会生成任何实际的输出物。如果不配置,则打包方式默认为 jar,表示将项目编译后的class文件打成jar包,可以供其他项目使用。

在父项目的pom.xml中配置模块信息,就是我们创建的两个Module:

<modules>
    <module>consumer</module>
    <module>producer</module>
</modules>

修改两个模块的application.yaml文件,设置其端口号:

server:
  # 应用服务 WEB 访问端口
  port: 58081

spring:
  application:
    # 应用名称
    name: consumer
server:
  # 应用服务 WEB 访问端口
  port: 58089

spring:
  application:
    # 应用名称
    name: producer

两个服务都能正常启动:
image.png

2. 注册中心 —— nacos

为了能够动态地管理微服务,需要引入注册中心。这里我们使用Nacos作为注册中心,它提供了服务注册与发现、健康检查等功能。

( 注意:由于Nacos是C/S架构,因此需要搭建Nacos的服务端,我们这里在本地搭建起了一个服务端,过程就不再赘述了。)

首先在父工程pom文件中添加依赖:

<dependencyManagement>
    <dependencies>
        // spring-boot依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        
        // spring-cloud-alibaba依赖
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${spring-cloud-alibaba.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        
        // 在Springboot2.4.x版本之后,需要此依赖用于加载bootstrap.yaml
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>${bootstap.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

这里spring-cloud-alibaba我们使用的是2021.0.4.0版本,可以查看版本说明

在子pom文件中引入依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

// nacos注册中心
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

给微服务中添加bootstrap.yaml文件,该配置文件用于程序引导时执行,设置基本不会变的系统级参数。比如上边application.yaml中的配置,就可以移到bootstrap.yaml中。

之后,可以在bootstrap.yaml中进行nacos的配置:

server:
  # 应用服务 WEB 访问端口
  port: 58081

spring:
  application:
    # 应用名称
    name: consumer

  # Nacos配置
  cloud:
    nacos:
      username: nacos
      password: nacos
      discovery:
        # Nacos 服务器地址
        server-addr: 127.0.0.1:8848
        # namespace,默认为public
        namespace: DEV
        # group,默认为DEFAULT_GROUP
        group: spring_cloud_demo
server:
  # 应用服务 WEB 访问端口
  port: 58089

spring:
  application:
    # 应用名称
    name: producer

  # Nacos配置
  cloud:
    nacos:
      username: nacos
      password: nacos
      discovery:
        # Nacos 服务器地址
        server-addr: 127.0.0.1:8848
        # namespace,默认为public
        namespace: DEV
        # group,默认为DEFAULT_GROUP
        group: spring_cloud_demo

登陆Nacos的管理页面,可以在我们设置的namespace下看到注册的服务列表。 image.png

3. 配置中心 —— nacos

nacos除了提供注册中心的功能外,还可以作为配置中心,用于统一的配置管理和动态配置项。

先使用普通的属性注入:
创建一个bean,用于测试配置项:

@Data
public class MyDatasource {
    private String url;
    private String username;
    private String password;
    private String dbType;
}

创建配置类,其中dbType属性使用@Value注解获取配置值,其它属性使用@ConfigurationProperties注入。

@Configuration
public class DatasourceConfiguration {

    @Value("${spring.dbType}")
    public String dbType;

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public MyDatasource myDatasource() {
        MyDatasource datasource = new MyDatasource();
        datasource.setDbType(dbType);
        return datasource;
    }
}

在application.yaml中进行配置:

spring:
  datasource:
    url: mysql_url
    username: mysql
    password: 123456

  dbType: mysql

创建Controller,提供外部调用的接口:

@Slf4j
@RestController
public class ProducerController {
    @Resource
    private MyDatasource dataSource;

    @RequestMapping("/invokeProducer")
    public String invokeProducer() {
        log.info("Database type is {}", dataSource.getDbType());
        log.info("Url is {}", dataSource.getUrl());
        return "succeed";
    }
}

先调用一下接口,看看结果: image.png

然后,使用Nacos提供的配置中心功能

我们在producer的pom中引入配置中心依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

在bootstrap.yaml中,增加配置中心的配置项:

server:
  # 应用服务 WEB 访问端口
  port: 58089

spring:
  application:
    # 应用名称
    name: producer

  # Nacos配置
  cloud:
    nacos:
      username: nacos
      password: nacos
      discovery:
        # Nacos 服务器地址
        server-addr: 127.0.0.1:8848
        # namespace,默认为public
        namespace: DEV
        # group,默认为DEFAULT_GROUP
        group: spring_cloud_demo

      config:
        # Nacos 服务器地址
        server-addr: 127.0.0.1:8848
        # namespace,默认为public
        namespace: DEV
        # group,默认为DEFAULT_GROUP
        group: producer
        # 配置文件格式,默认为properties
        file-extension: yaml

在nacos管理页面的配置中心,增加如下配置(注意namespace不要弄错):

spring:
  datasource:
    url: postgresql_url
    username: postgresql
    password: 123456

  dbType: postgresql

image.png

点击发布,并调用接口,可以看到控制台有如下打印: image.png

奇怪了,明明已经刷新配置了,为什么dbType的值还是之前的值呢?

这里需要注意,如果使用的是@Value注解,需要使用@RefreshScope标记该bean是可以刷新的,如果使用的是@ConfigurationProperties注解,则不需要使用。

我们增加@RefreshScope注解后,再次尝试:

// 增加@RefreshScope
@RefreshScope
@Configuration
public class DatasourceConfiguration {

    @Value("${spring.dbType}")
    public String dbType;

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public MyDatasource myDatasource() {
        MyDatasource datasource = new MyDatasource();
        datasource.setDbType(dbType);
        return datasource;
    }
}

image.png 可以看到,配置成功刷新了。

4. 远程调控 —— openFeign

我们在微服务之间进行调用,除了可以使用restTemplate之外,还可以使用openFeign。

创建一个新模块feign-client,并在父工程的pom中增加配置和依赖:

<modules>
    <module>consumer</module>
    <module>producer</module>
    <module>feign-client</module>
</modules>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>${spring-cloud.version}</version>
</dependency>

<dependency>
    <groupId>org.example</groupId>
    <artifactId>feign-client</artifactId>
    <version>${revision}</version>
</dependency>

在feign-client的pom中增加依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

创建ProvducerClient接口:

/**
 * 声明producer客户端
 */
@FeignClient(name = "producer")
public interface ProducerClient {
    @RequestMapping("/invokeProducer")
    String invokeProducer();
}

在consumer模块中引入feign-client的依赖,并创建Controller调用producer的接口:

<dependency>
    <groupId>com.example</groupId>
    <artifactId>feign-client</artifactId>
</dependency>
@Slf4j
@RestController
public class ConsumerController {

    @Resource
    private ProducerClient producerClient;

    @RequestMapping("/invokeConsumer")
    public String invokeConsumer() {
        log.info("Consumer received request.");
        String response = producerClient.invokeProducer();
        log.info("Response from producer is {}", response);
        return response;
    }
}

在consumer启动类上增加配置:

@SpringBootApplication
@EnableFeignClients(basePackages = "com.example.feignclient.client")
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }

}

尝试启动项目,发现如下报错:

Caused by: java.lang.IllegalStateException: No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?
	at org.springframework.cloud.openfeign.FeignClientFactoryBean.loadBalance(FeignClientFactoryBean.java:382) ~[spring-cloud-openfeign-core-3.1.5.jar:3.1.5]
	at org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget(FeignClientFactoryBean.java:427) ~[spring-cloud-openfeign-core-3.1.5.jar:3.1.5]
	at org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:402) ~[spring-cloud-openfeign-core-3.1.5.jar:3.1.5]
	at org.springframework.cloud.openfeign.FeignClientsRegistrar.lambda$registerFeignClient$0(FeignClientsRegistrar.java:235) ~[spring-cloud-openfeign-core-3.1.5.jar:3.1.5]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1249) ~[spring-beans-5.3.23.jar:5.3.23]
	at调控rg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1191) ~[spring-beans-5.3.23.jar:5.3.23]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.23.jar:5.3.23]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.23.jar:5.3.23]
	... 30 common frames omitted

因为在新版本的openFeign,已经不再使用Ribbon做负载均衡,而是使用loadbalancer了,因此还需要对其进行引入,具体的我们在后边说明。

5. 负载均衡 —— loadbalancer

上边说到在使用feign的时候,需要引入loadbalancer作为负载均衡。

在父工程pom和feign-client的pom中引入依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    <version>${spring-cloud.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

为了验证负载均衡,我们先修改其controller层,让其返回所在节点的port:

@Slf4j
@RestController
public class ProducerController {
    @Resource
    private MyDatasource dataSource;

    @RequestMapping("/invokeProducer")
    public String invokeProducer(HttpServletRequest httpServletRequest) {
        log.info("Database type is {}", dataSource.getDbType());
        log.info("Url is {}", dataSource.getUrl());
        // 返回producer的port
        return "Producer port is " + httpServletRequest.getLocalPort();
    }
}

然后我们启动两个producer服务,设置其port分别为58088和58089,并多次调用接口: image.png 可以看到,通过负载均衡,consumer以轮询的方式,分别调用了两个producer服务。

6. 网关 —— gateway

上边我们启动了多个producer,那如果我们也启动了多个consumer,那每次调用的时候不是都得换url吗?而且这样岂不是把所有的地址暴露给外部了?

可以使用网关来解决这个问题。

创建一个模块gateway,添加依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
    <groupId>com.example</groupId>
    <artifactId>feign-client</artifactId>
</dependency>

添加bootstrap.yaml配置文件:

server:
  # 应用服务 WEB 访问端口
  port: 58080

spring:
  application:
    # 应用名称
    name: gateway

  # Nacos配置
  cloud:
    nacos:
      username: nacos
      password: nacos
      discovery:
        # Nacos 服务器地址
        server-addr: 127.0.0.1:8848
        # namespace,默认为public
        namespace: DEV
        # group,默认为DEFAULT_GROUP
        group: spring_cloud_demo

      config:
        # Nacos 服务器地址
        server-addr: 127.0.0.1:8848
        # namespace,默认为public
        namespace: DEV
        # group,默认为DEFAULT_GROUP
        group: gateway
        # 配置文件格式,默认为properties
        file-extension: yaml

gateway中创建controller,调用consumer接口:

@RestController
public class GatewayController {

    @Resource
    private ConsumerClient consumerClient;

    @RequestMapping("/invokeConsumer")
    public String invokeConsumer() {
        return consumerClient.invokeConsumer();
    }
}

我们启动2个consumer,端口分别为58081和58082,也启动2个producer,端口分别为58088和58089,调用网关的接口,发现报错:

java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3
	at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83) ~[reactor-core-3.4.24.jar:3.4.24]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
	*__checkpoint ⇢ HTTP GET "/invokeConsumer" [ExceptionHandlingWebHandler]

这是因为gateway是基于WebFlux非阻塞模型的,因此需要使用异步的方式去调用。

修改代码:

@RestController
public class GatewayController {

    @Resource
    private ConsumerClient consumerClient;

    ExecutorService executorService = Executors.newFixedThreadPool(3);

    @RequestMapping("/invokeConsumer")
    public String invokeConsumer() throws ExecutionException, InterruptedException {
        Future<String> response = executorService.submit(() -> consumerClient.invokeConsumer());
        return response.get();
    }
}

再次调用接口,又出现了新异常:

java.util.concurrent.ExecutionException: feign.codec.DecodeException: No qualifying bean of type 'org.springframework.boot.autoconfigure.http.HttpMessageConverters' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	at java.util.concurrent.FutureTask.report(FutureTask.java:122) ~[na:1.8.0_201]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
	*__checkpoint ⇢ HTTP GET "/invokeConsumer" [ExceptionHandlingWebHandler]

因此我们需要创建HttpMessageConverters的Bean注入容器中:

@Configuration
public class GatewayConfiguration {
    // HttpMessageConverter负责转换HTTP的请求和响应。
    // Spring Cloud Gateway是基于WebFlux的,是ReactiveWeb。所以HttpMessageConverters不会自动注入。
    @Bean
    @ConditionalOnMissingBean
    public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
        return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
    }
}

现在再来多次调用接口,打印如下: image.png

image.png 可以看到,通过网关,实现了在不修改访问地址的前提下,实现了内部服务的负载均衡访问。

当然,也可以通过配置路由,直接实现请求的转发,而不需要通过controller:

spring:
  cloud:
    gateway:
      routes:
        - id: consumer
          uri: lb://consumer
          predicates:
            - Path=/invokeConsumer

这里可以通过匹配/invokeConsumer,路由到consumer服务,并通过lb进行负载均衡。

7. 断路器 —— sentinel

虽然上边已经可以完成基本的服务间调用,但是为了防止大流量场景下系统宕机,还需要对流量进行控制,这就可以使用sentinel来实现。

引入依赖:

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

在application.yaml中进行配置:

sentinel:
  # 服务启动时就直接建立心跳,不需要等到第一次访问接口,才连接sentinel
  eager: true
  # 控制台地址
  transport:
    dashboard: localhost:8081

对代码做一些微调,增加一个service层,使用@SentinelResource注解标注了方法,并设置了资源名称:

@Service
public class GatewayService {
    @Resource
    private ConsumerClient consumerClient;

    ExecutorService executorService = Executors.newFixedThreadPool(3);

    @SentinelResource(value = "invokeConsumer")
    public String invokeConsumer() throws ExecutionException, InterruptedException {
        Future<String> response = executorService.submit(() -> consumerClient.invokeConsumer());
        return response.get();
    }
}

sentinel也需要启动服务端,打开sentinel控制台,可以对流控规则、熔断规则等进行配置: image.png

这里配置了一条流控规则:允许访问该资源的最大QPS为3 image.png

使用jmeter调用接口,在一秒内发送了5个请求,可以看到确实只允许通过了3个请求,其余两个被拒绝了 image.png

有没有办法在调用失败时,做一些相应的处理呢?

答案是可以,@SentinelResource注解提供了几个属性:

fallbackClass表示发生异常时的回调类,fallback设置回调方法;
blockHandlerClass表示进入流控时的回调类,blockHandler设置回调方法。

修改代码:

@Service
public class GatewayService {
    @Resource
    private ConsumerClient consumerClient;

    ExecutorService executorService = Executors.newFixedThreadPool(3);

    // fallback为发生异常的回调方法,blockHandler为进入流控时的回调方法
    @SentinelResource(value = "invokeConsumer", fallbackClass = FallbackConfigurer.class, fallback = "fallback",
            blockHandlerClass = BlockHandlerConfigurer.class, blockHandler = "blockHandler")
    public String invokeConsumer() throws ExecutionException, InterruptedException {
        Future<String> response = executorService.submit(() -> consumerClient.invokeConsumer());
        return response.get();
    }
}

其中,@SentinelResource中的属性配置类如下:

/**
 * 发生异常时的回调方法
 */
public class FallbackConfigurer {
    public static String fallback() {
        return "发生了异常.";
    }
}
/**
 * 进入流控时的回调方法
 */
public class BlockHandlerConfigurer {
    public static String blockHandler(BlockException blockException) {
        return "发生了流控: " + blockException;
    }
}

如果发生了异常,会得到如下响应: image.png 如果进入了流控,会得到如下响应: image.png

8. 一些思考

(1) nacos如何共享配置?

如果多个服务都需要同样的配置,该怎么做呢?

可以使用共享配置来实现。

比如可以在nacos中增加以下配置:

feign:
  # Feign整合Sentinel
  sentinel:
    enabled: true

  client:
    config:
      # 设置通用配置
      default:
        # client连接超时为100毫秒
        # 连接时间不宜过长,防止依赖服务负载过高情况下活跃连接都在长时间尝试建立连接,建议设置比较短以便快速失败
        connectTimeout: 100
        # client响应超时为1秒
        # 单个接口响应时间不宜过长,建议为1秒,超过1秒的一般都需要优化接口,如果无法优化建议走独立配置
        readTimeout: 1000

image.png

在需要使用该配置的服务的bootstrap.yaml中增加shared-configs配置即可(如果需要额外的扩展配置,也可以使用extension-configs配置):

spring:
  # Nacos配置
  cloud:
    nacos:
      config:
        # 公共配置文件
        shared-configs:
          - data-id: feign-config.yaml
            group: shared
            refresh: true

        # 扩展配置文件,优先级大于shared-configs,在其后进行加载
        extension-configs:
          - data-id: xxx.yaml
            group: xxx
            refresh: true

更多详情可以参考这篇文章

(2) nacos的配置如何持久化?

在单机模式下,nacos默认使用一个内嵌式数据库实现配置存储,如果想使用mysql进行配置存储应该如何实现呢?

在nacos-server的conf目录中,有一个nacos-mysql.sql文件,将其导入Mysql中就会创建nacos所需要的一系列表: image.png 在同目录的application.properties文件中,或者在项目中的application.yaml中,填写mysql的连接信息: image.png 可以看到,在config_info表中,就能看到我们在nacos上配置的文件: image.png

(3) 如何使用连接线程池呢?

OpenFeign的底层是通过http/https协议进行通信的,默认使用的是HttpURLConnection,每次请求都会建立、关闭连接,比较浪费性能,可以引入httpclient作为底层的通信框架,它支持连接池。

引入依赖:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

增加配置:

feign:
  httpclient:
    # 设置单个HOST最大连接数为50个,可根据高峰期调用频率来调整
    maxConnectionsPerRoute: 50
    # 设置全局最大连接数为300个连接,可根据具体有多少FeignClient来决定,比如一个HOST最多50个连接,一个有8个HOST,每个HOST调用频率有高有低,可折中取值300
    maxConnections: 300
    # 设置连接存活时间为900秒,超过该时间后空闲连接会被回收,注意的是如果你通过Java Config覆盖默认ApacheHttpClient,一定要创建定时器来检测无用连接
    timeToLive: 900

(4) 负载均衡策略如何修改?

之前我们使用loadbalancer时,没有配置负载均衡策略,默认的是轮询策略,如果想修改为随机策略可以配置一个RandomLoadBalancer。

/**
 * 负载均衡策略,默认为round-robin
 */
public class LoadBalancerConfiguration {
    @Bean
    public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
                                                                                   LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
//        return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name,
//                ServiceInstanceListSupplier.class), name);
        return new RandomLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

然后使用@LoadBalancerClient进行配置:

/**
 * 声明consumer客户端
 */
@FeignClient(name = "consumer")
// 根据name去注册中心找对应的实例地址
@LoadBalancerClient(name = "consumer", configuration = LoadBalancerConfiguration.class)
public interface ConsumerClient {
    @RequestMapping("/invokeConsumer")
    String invokeConsumer();
}

(5) 如何持久化sentinal配置呢?

每次项目重启后,sentinel中配置的规则都会丢失,可以利用nacos对其进行持久化。

引入依赖:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

在sentinel配置下追加如下配置:

spring:
  cloud:
    sentinel:
      # 服务启动时就直接建立心跳,不需要等到第一次访问接口,才连接sentinel
      eager: true
      # 控制台地址
      transport:
        dashboard: localhost:8081

      # 持久化
      datasource:
        ds1: # 随便起名字
          nacos:
            server-addr: localhost:8848
            namespace: DEV
            dataId: gateway # 微服务名称
            groupId: gateway
            data-type: json
            rule-type: flow # 流控规则

新增nacos配置:

[   
    {
        "resource": "/invokeConsumer", // 资源名称
        "limitApp": "default",  // 来源应用
        "grade": 1, // 阈值类型:0表示线程数,1表示QPS
        "count": 3, // 单机阈值
        "strategy": 0, // 流控模式:0表示直接,1表示关联,2表示链路
        "controlBehavior": 0, //流控效果:0表示快速失败,1表示warm up,2表示排队等待 
        "clusterMode": false // 是否集群
    }
]