SpringCloud-Sentinel實現服務限流、熔斷、降級,整合Nacos實現持久化


Sentinel簡介

隨着微服務的流行,服務與服務之間的穩定性變得越來越重要。Sentinel以流量為切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。

Sentinel具有如下特性:

  • 豐富的應用場景:承接了阿里巴巴近十年的雙十一大促流量的核心場景,例如秒殺,可以實時熔斷下游不可用服務。
  • 完備的實時監控:同時提供實時的監控功能。可以在控制台中看到接入應用的單台機器秒級數據,甚至500台以下規模的集群的匯總運行情況。
  • 廣泛的開源生態:提供開箱即用的與其他開源框架/庫的整合模塊,例如與 SpringCloud 、Dubbo、 gRPC的整合。
  • 完善的 SPI 擴展點:提供簡單易用、完善的 SPI 擴展點。可以通過實現擴展點,快速的定制邏輯。

一、安裝Sentinel控制台

Sentinel控制台是一個輕量級的控制台應用,它可用於實時查看單機資源監控及集群資源匯總,並提供了一系列的規則管理功能,如流控規則、降級規則、熱點規則等。

從官網下載Sentinel,這里使用的是sentinel-dashboard-1.7.2.jar文件,下載地址:
https://github.com/alibaba/Sentinel/releases

下載完成后再命令行輸入以下命令運行Sentinel控制台:

java -jar sentinel-dashboard-1.7.2.jar

Sentinel控制台默認運行在8080端口上,登錄賬號和密碼均為sentinel,通過如下地址進行訪問:http://localhost:8080
在這里插入圖片描述
Sentinel控制台可以查看單台機器的實時監控數據。
在這里插入圖片描述

二、創建springboot-sentinel模塊

這里我們創建一個springboot-sentinel模塊,用於演示Sentinel的熔斷與限流功能。

在pom.xml中添加相關依賴,這里我們使用Nacos作為注冊中心,所以需要同時引入Nacos的依賴。

  <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.2.2.RELEASE</version>
      <relativePath/>
  </parent>

  <properties>
      <java.version>1.8</java.version>
      <spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
  </properties>

  <dependencyManagement>
      <dependencies>
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-dependencies</artifactId>
              <version>${spring-cloud.version}</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
          <dependency>
              <groupId>com.alibaba.cloud</groupId>
              <artifactId>spring-cloud-alibaba-dependencies</artifactId>
              <version>2.1.1.RELEASE</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
      </dependencies>
  </dependencyManagement>

  <dependencies>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</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-sentinel</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>

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

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
          <exclusions>
              <exclusion>
                  <groupId>org.junit.vintage</groupId>
                  <artifactId>junit-vintage-engine</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
  </dependencies>


  <build>
      <plugins>
          <plugin>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
      </plugins>
  </build>

在application.yml中添加相關配置,主要是配置了Nacos和Sentinel控制台地址:

server:
  port: 8401

spring:
  application:
    name: springboot-sentinel
  cloud:
    nacos:
      discovery:
        namespace: dev
        server-addr: 192.168.0.130:8848
    sentinel:
      transport:
        # 配置Sentinel dashborad地址
        dashboard: http://localhost:8080
        port: 8719
      datasource:
        - nacos:
            server-addr: 192.168.0.130:8848
            data-id: ${spring.application.name}-flow-rules
            group-id: DEFAULT_GROUP
            data-type: json
            rule-type: flow

service-url:
  user-service: http://192.168.0.130:8501

management:
  endpoints:
    web:
      exposure:
        include: '*'
feign:
  sentinel:
    enabled: true

三、限流功能

Sentinel Starter 默認為所有的 HTTP 服務提供了限流埋點,我們也可以通過使用@SentinelResource來自定義一些限流行為。

四、創建RateLimitController類

用於測試熔斷和限流功能。

package com.lee.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.lee.handle.CustomBlockHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/rateLimit")
public class RateLimitController {

    /**
     * 按資源名稱限流,需要指定限流處理邏輯
     *
     * @return
     */
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource", blockHandler = "handleException")
    public Map<String,Object> byResource() {
        Map<String,Object> result = new HashMap<>();
        result.put("name","按資源名稱限流");
        result.put("code",200);
        return result ;
    }

    /**
     * 按url限流,有默認的限流處理邏輯
     *
     * @return
     */
    @GetMapping("byUrl")
    @SentinelResource(value = "byUrl", blockHandler = "handleException")
    public Map<String,Object> byUrl() {
        Map<String,Object> result = new HashMap<>();
        result.put("name","按url限流");
        result.put("code",200);
        return result ;
    }

    public Map<String,Object> handleException(BlockException exception) {
        Map<String,Object> result = new HashMap<>();
        result.put("name",exception.getClass().getCanonicalName());
        result.put("code",200);
        return result ;
    }

    @GetMapping("/customBlockHandler")
    @SentinelResource(value = "customBlockHandler", blockHandler = "handleException", blockHandlerClass = CustomBlockHandler.class)
    public Map<String,Object> blockHandler() {
        Map<String,Object> result = new HashMap<>();
        result.put("name","限流成功");
        result.put("code",200);
        return result ;
    }
}

1.根據資源名稱限流

我們可以根據@SentinelResource注解中定義的value(資源名稱)來進行限流操作,但是需要指定限流處理邏輯。

流控規則可以在Sentinel控制台進行配置,由於我們使用了Nacos注冊中心,我們先啟動Nacos和sentinel-service;

由於Sentinel采用的懶加載規則,需要我們先訪問下接口,Sentinel控制台中才會有對應服務信息,我們先訪問下該接口:
http://localhost:8401/rateLimit/byUrl

在Sentinel控制台配置流控規則,根據@SentinelResource注解的value值:
在這里插入圖片描述
快速訪問上面的接口,可以發現返回了自己定義的限流處理信息:
在這里插入圖片描述

2.根據URL限流

我們還可以通過訪問的URL來限流,會返回默認的限流處理信息。

在Sentinel控制台配置流控規則,使用訪問的URL:
在這里插入圖片描述

多次訪問該接口,會返回默認的限流處理結果:http://localhost:8401/rateLimit/byUrl

在這里插入圖片描述

3.自定義限流處理邏輯

我們可以自定義通用的限流處理邏輯,然后在@SentinelResource中指定。

創建 CustomBlockHandler 類用於自定義限流處理邏輯:

package com.lee.handle;

import com.alibaba.csp.sentinel.slots.block.BlockException;

import java.util.HashMap;
import java.util.Map;

public class CustomBlockHandler {

    public static Map<String,Object> handleException(BlockException exception) {

        Map<String,Object> result = new HashMap<>();
        result.put("name","自定義限流信息");
        result.put("code",200);
        return result ;
    }
}

在RateLimitController中自定義限流處理邏輯:

package com.lee.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.lee.handle.CustomBlockHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/rateLimit")
public class RateLimitController {

    @GetMapping("/customBlockHandler")
    @SentinelResource(value = "customBlockHandler", blockHandler = "handleException", blockHandlerClass = CustomBlockHandler.class)
    public Map<String,Object> blockHandler() {
        Map<String,Object> result = new HashMap<>();
        result.put("name","限流成功");
        result.put("code",200);
        return result ;
    }
}

五、熔斷功能

Sentinel 支持對服務間調用進行保護,對故障應用進行熔斷操作,這里我們使用RestTemplate來調用springboot-provider服務所提供的接口來演示下該功能。

springboot-provider服務提供的接口非常簡單:

package com.lee.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class TestController {


    @GetMapping("/user/{id}")
    public Map<String,Object> getInfo(@PathVariable(value = "id") String id) {

        if("1".equals(id)) {
            throw new RuntimeException("remote func is fail");
        }

        Map<String,Object> result = new HashMap<>();
        result.put("reqData",id);
        result.put("code","200");

        return result ;
    }
}

創建RestTemplate

package com.lee.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class CusConfig {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

添加 CircleBreakerController 類,定義對springboot-provider提供接口的調用:

package com.lee.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;


@RestController
@RequestMapping("/breaker")
public class CircleBreakerController {

    private static final Logger LOGGER = LoggerFactory.getLogger(CircleBreakerController.class);

    @Autowired
    private RestTemplate restTemplate;

    @Value("${service-url.user-service}")
    private String userServiceUrl;

    @GetMapping("/fallback/{id}")
    @SentinelResource(value = "fallback", fallback = "handleFallback")
    public Map<String,Object> fallback(@PathVariable Long id) {
        Map<String,Object> forObject = restTemplate.getForObject(userServiceUrl + "/user/{1}", Map.class, id);
        System.out.println(forObject);
        return forObject;
    }

    @GetMapping("/fallbackException/{id}")
    @SentinelResource(value = "fallbackException", fallback = "handleFallback2", exceptionsToIgnore = {NullPointerException.class})
    public Map<String,Object> fallbackException(@PathVariable Long id) {
        if (id == 1) {
            throw new IndexOutOfBoundsException();
        } else if (id == 2) {
            throw new NullPointerException();
        }

        return restTemplate.getForObject(userServiceUrl + "/user/{1}", Map.class, id);
    }

    public Map<String,Object> handleFallback(Long id) {
        Map<String,Object> result = new HashMap<>();
        result.put("name","service degradation");
        result.put("code",200);
        return result ;
    }

    public Map<String,Object> handleFallback2(Long id, Throwable e) {
        LOGGER.error("handleFallback2 id:{},throwable class:{}", id, e.getClass());
        Map<String,Object> result = new HashMap<>();
        result.put("name","service degradation");
        result.put("code",200);

        return result ;
    }
}

啟動springboot-provider和springboot-sentinel服務:

如果id為1 的情況會返回服務降級結果:
http://localhost:8401/breaker/fallback/1
在這里插入圖片描述
id為2時正常返回:
在這里插入圖片描述

由於我們使用了 exceptionsToIgnore 參數忽略了 NullPointerException ,所以我們訪問接口報空指針時不會發生服務降級:
http://localhost:8401/breaker/fallbackException/2

在這里插入圖片描述

六、與Feign結合使用

Sentinel也適配了Feign組件,我們使用Feign來進行服務間調用時,也可以使用它來進行熔斷。

首先我們需要在pom.xml中添加Feign相關依賴:

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

在application.yml文件中打開Sentinel對Feign的支持:

# 打開sentinel對feign的支持
feign:
  sentinel:
    enabled: true

在應用啟動類上添加@EnableFeignClients啟動Feign的功能;

創建一個UserService接口,用於定義對springboot-provider服務的調用:

package com.lee.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.Map;

@FeignClient(value = "springboot-provider", fallback = UserFallbackService.class)
public interface UserService {

    @GetMapping("/user/{id}")
    Map<String,Object> getInfo(@PathVariable Long id);
}

創建UserFallbackService類實現UserService接口,用於處理服務降級邏輯:

package com.lee.service;

import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
public class UserFallbackService implements UserService {

    @Override
    public Map<String,Object> getInfo(Long id){

        Map<String,Object> result = new HashMap<>();
        result.put("name","service lower level");
        result.put("code",200);

        return result ;
    }
}

在UserFeignController中使用UserService通過Feign調用springboot-provider服務中的接口:

package com.lee.controller;

import com.lee.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequestMapping("/user")
public class UserFeignController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public Map<String,Object> getUser(@PathVariable Long id) {
        return userService.getInfo(id);
    }

}

在啟動類SentinelServiceApplication添加@EnableFeignClients注解

package com.lee;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class App {

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

}

調用如下接口會發生服務降級,返回服務降級處理信息:http://localhost:8401/user/1
在這里插入圖片描述

七、使用Nacos存儲規則

默認情況下,當我們在Sentinel控制台中配置規則時,控制台推送規則方式是通過API將規則推送至客戶端並直接更新到內存中。一旦我們重啟應用,規則將消失。下面我們介紹下如何將配置規則進行持久化,以存儲到Nacos為例。

1. 原理示意圖

在這里插入圖片描述
首先我們直接在配置中心創建規則,配置中心將規則推送到客戶端;

Sentinel控制台也從配置中心去獲取配置信息。

2. 功能演示

先在pom.xml中添加相關依賴:

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

修改application.yml配置文件,添加Nacos數據源配置:

spring:
  application:
    name: springboot-sentinel
  cloud:
    nacos:
      discovery:
        namespace: dev
        server-addr: 192.168.0.130:8848
    sentinel:
      transport:
        # 配置Sentinel dashborad地址
        dashboard: http://localhost:8080
        port: 8719
      datasource:
        - nacos:
            server-addr: 192.168.0.130:8848
            data-id: ${spring.application.name}-flow-rules
            group-id: DEFAULT_GROUP
            data-type: json
            rule-type: flow

在Nacos中添加配置:

在這里插入圖片描述
添加配置信息如下:

[
    {
        "app":"springboot-sentinel",
        "clusterConfig":{
            "fallbackToLocalWhenFail":true,
            "sampleCount":10,
            "strategy":0,
            "thresholdType":0,
            "windowIntervalMs":1000
        },
        "clusterMode":false,
        "controlBehavior":0,
        "count":1,
        "gmtCreate":1617343597193,
        "gmtModified":1617343597193,
        "grade":1,
        "id":1,
        "ip":"192.168.0.130",
        "limitApp":"default",
        "port":8720,
        "resource":"byUrl",
        "strategy":0
    }
]

常規參數解釋:

  • resource:資源名稱;
  • limitApp:來源應用;
  • grade:閾值類型,0表示線程數,1表示QPS;
  • count:單機閾值;
  • strategy:流控模式,0表示直接,1表示關聯,2表示鏈路;
  • controlBehavior:流控效果,0表示快速失敗,1表示Warm Up,2表示排隊等待;
  • clusterMode:是否集群。

發現Sentinel控制台已經有了如下限流規則:
在這里插入圖片描述

快速訪問測試接口,可以發現返回了限流處理信息:
在這里插入圖片描述

到這已基本完成對sentinel的基本使用。現在從nacos修改的配置信息能夠同步到sentinel,但是從sentinel控制台修改的數據卻無法同步到nacos中,這樣兩邊都修改數據信息的話,對導致非常嚴重的后果。

3. Sentinel Dashboard集成Nacos實現規則同步

Sentinel Dashboard的流控規則下的所有操作,都會調用Sentinel-Dashboard源碼中的FlowControllerV1類,這個類中包含流控規則本地化 的CRUD操作。

另外,在com.alibaba.csp.sentinel.dashboard.controller.v2包下存在一個FlowControllerV2類,這個類同樣提供流控規則的CRUD,和V1版本不同的是,它可以實現指定數據源的規則拉取和發布。

@RestController
@RequestMapping(value = "/v2/flow")
public class FlowControllerV2 {

    private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);

    @Autowired
    private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;

    @Autowired
    @Qualifier("flowRuleDefaultProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
    @Autowired
    @Qualifier("flowRuleDefaultPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

FlowControllerV2依賴以下兩個非常重要的類:

  • DynamicRuleProvider: 動態規則的拉取,從指定數據源中獲取流控規則后在Sentinel Dashboard中展示。
  • DynamicRulePublisher: 動態規則的發布,將在Sentinel Dashboard中修改的規則同步到指定數據源中。

我們可以擴展這兩個類,然后集成Nacos來實現Sentinel Dashboard規則的同步。

4. Sentinel Dashboard源碼修改

源碼下載地址:https://github.com/alibaba/Sentinel/releases

修改源碼,具體步驟如下:

  1. 使用IDEA工具打開sentinel-dashboard工程。
  2. 在pom.xml中把 sentinel-datasource-nacos 依賴的 注釋掉。 在這里插入圖片描述
  3. 修改resources/app/scripts/directives/sidebar/sidebar.html文件中下面這段代碼,將dashboard.flowV1改成dashboard.flow,也就是去掉V1。修改之后,會調用FlowControllerV2中的接口。如果不修改,則調用FlowControllerV1中的接口(也可自行修改接口實現)
    在這里插入圖片描述
  4. 在com.alibaba.csp.sentinel.dashboard.rule包中創建一個nacos包,並創建一個類用來加載外部化配置。

package com.alibaba.csp.sentinel.dashboard.rule.nacos;


public final class NacosConfigUtil {

    public static final String GROUP_ID = "SENTINEL_GROUP";
    
    public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules";
    public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-rules";
    public static final String CLUSTER_MAP_DATA_ID_POSTFIX = "-cluster-map";

    /**
     * cc for `cluster-client`
     */
    public static final String CLIENT_CONFIG_DATA_ID_POSTFIX = "-cc-config";
    /**
     * cs for `cluster-server`
     */
    public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX = "-cs-transport-config";
    public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX = "-cs-flow-config";
    public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX = "-cs-namespace-set";

    private NacosConfigUtil() {}
}
  1. 創建一個NacosConfig 配置類

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigFactory;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.Properties;

/**
 * @author Eric Zhao
 * @since 1.4.0
 */
@Configuration
public class NacosConfig {

    @Value("${sentinel.nacos.serverAddr}")
    private String nacosAddr ;

    @Bean
    public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
        return JSON::toJSONString;
    }

    @Bean
    public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
        return s -> JSON.parseArray(s, FlowRuleEntity.class);
    }

    @Bean
    public ConfigService nacosConfigService() throws Exception {

        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR,nacosAddr);
        return  NacosFactory.createConfigService(properties);
    }
}

  1. 實現動態從Nacos配置中心獲取流控規則
@Component("flowRuleNacosProvider")
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {

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

    @Value("${sentinel.nacos.group-id}")
    private String groupId ;

    @Autowired
    private ConfigService configService ;

    @Override
    public List<FlowRuleEntity> getRules(String appName) throws Exception {

//        Properties properties = new Properties();
//        properties.put(PropertyKeyConst.SERVER_ADDR, nacosAddr);
//        ConfigService configService = NacosFactory.createConfigService(properties);
//        String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, groupId, 5000);


//        String serverAddr = "192.168.0.130:8848";
//        String dataId = "springboot-sentinel-flow-rules";
//        String group = "DEFAULT_GROUP";
//        Properties properties = new Properties();
//        properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
//        ConfigService configService = NacosFactory.createConfigService(properties);
//        String rules = configService.getConfig(dataId, group, 5000);

        System.out.println(appName+NacosConfigUtil.FLOW_DATA_ID_POSTFIX);
        String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
                groupId, 5000);
        if (StringUtil.isEmpty(rules)) {
            return new ArrayList<>();
        }
        return converter.convert(rules);
    }
}
  1. 創建一個流控規則發布類,在Sentinel Dashboard上修改完配置后,需要調用該發布方法將數據持久化到Nacos中。
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {

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

    @Value("${sentinel.nacos.group-id}")
    private String groupId ;

    @Autowired
    private ConfigService configService ;

    @Override
    public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
        AssertUtil.notEmpty(app, "app name cannot be empty");
        if (rules == null) {
            return;
        }

//        String serverAddr = "192.168.0.241:8848";
//        String dataId = "springboot-docker-flow-rules";
//        String group = "DEFAULT_GROUP";
//        Properties properties = new Properties();
//        properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
//        ConfigService configService = NacosFactory.createConfigService(properties);
//
//        configService.publishConfig(dataId,group,converter.convert(rules));

        configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
                groupId, converter.convert(rules));
    }
}
  1. 修改FlowControllerV2類,將上面配置的兩個類注入進來,表示規則的拉取和規則的發布統一用我們前面定義的兩個實例,然后將FlowControllerV2這個類中的代碼覆蓋FlowControllerV1的代碼。
@RestController
@RequestMapping(value = "/v2/flow")
public class FlowControllerV2 {

    private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);

    @Autowired
    private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;

    @Autowired
    @Qualifier("flowRuleNacosProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
    @Autowired
    @Qualifier("flowRuleNacosPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
  1. 在application.properties文件中添加Nacos服務相關配置:
sentinel.nacos.serverAddr=192.168.0.241:8848
sentinel.nacos.namespace=
sentinel.nacos.group-id=DEFAULT_GROUP
  1. 打包
mvn clean package 
  1. 修改sentinel控制台數據,則會同步到nacos中

修改前
在這里插入圖片描述
修改后
在這里插入圖片描述
nacos中
在這里插入圖片描述

項目地址(包含編譯好的sentinel1.7.2版本的dashboard):https://gitee.com/enthusiasts/sentinel-nacos.git

參考文章:
https://blog.csdn.net/ThinkWon/article/details/103770879
https://www.jianshu.com/p/deb7daa715af


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM