sentinel 持久化


1. 概述

在前面的關於Sentinel的使用中,可以發現,Sentinel-dashboard配置的規則,在我們的微服務以及控制台重啟的時候就清空了,因為他是基於內存的.

所以我們有必要將規則配置進行持久化, Sentinel 為我們提供了多種方式,多種選擇:

image-20210408135947884

官方文檔:https://github.com/alibaba/Sentinel/wiki/在生產環境中使用-Sentinel

而最推薦的方式為Push模式,

我們可以將規則配置到注冊中心中,例如ZooKeeper, Nacos, Apollo等等,當我們的客戶端去連接時,將配置信息實時推送到各個客戶端,概念圖如下:

image-20210408140336138

下面以Nacos 為例

2. 以Nacos演示

首先我們觀察一下,沒有注冊Nacos的情況

手動注冊規則,並進行訪問:


@RestController
@RequestMapping("test")
@Slf4j
public class TestController {

    @Autowired
    private TestService testService;

    /**
     * 加載此類后執行
     */
    @PostConstruct
    public void init() {
        List<FlowRule> rules = new ArrayList<>();
        //新建一個規則
        FlowRule rule = new FlowRule();
        //保護的資源
        rule.setResource("HelloWorld");
        //設置為QPS的規則類型
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        //值為2,則表示每秒只能訪問此資源兩次
        rule.setCount(2);
        rules.add(rule);
        //加載此資源
        FlowRuleManager.loadRules(rules);
    }

    @GetMapping("testB")
    @SentinelResource(value = "HelloWorld",blockHandler = "handler" ,blockHandlerClass = CustomerBlockHandler.class)
    public void testA() {
        System.out.println("業務代碼執行完畢!");
    }
}

打印如下

業務代碼執行完畢!
業務代碼執行完畢!
方法被流控
方法被流控
方法被流控
方法被流控
業務代碼執行完畢!
業務代碼執行完畢!
方法被流控
方法被流控

控制台流控規則顯示如下

image-20210408112155405

說明此時本地注冊的流控規則生效

使用Nacos配置:

添加依賴(pom):

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

添加訪問數據源配置(yaml):

server:
  port: 8401
spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    sentinel:
      transport: 
        dashboard: 127.0.0.1:8080
        port: 8719  
      datasource:
        dsl: # 名稱隨意
          nacos:
            server-addr: 192.168.100.108:8848 # nacos地址
            dataId: cloudalibaba-sentinel-service #nacos配置的dataId
            groupId: DEFAULT_GROUP # nacos配置的groupId
            data_type: json # 配置文件類型
            rule-type: flow #規則類型
management:
  endpoints:
    web:
      exposure:
        include: "*"
        

此時我們再訪問testB 接口,發現此方法已經無法被流控,並且 控制台也沒有顯示此流控規則了, 說明 我們從Nacos中拉取規則時, 將覆蓋本地規則,此時 Nacos 我們還沒有配置,則 此時流控為空

業務代碼執行完畢!
業務代碼執行完畢!
業務代碼執行完畢!
業務代碼執行完畢!
業務代碼執行完畢!
業務代碼執行完畢!
業務代碼執行完畢!
業務代碼執行完畢!
業務代碼執行完畢!
業務代碼執行完畢!
業務代碼執行完畢!

image-20210408112328895

在Nacos中添加流控配置:

配置如下,其中 DataId ,GroupId, 配置類型 ,要和客戶端中配置的一致,此流控規則為 QPS 為1

image-20210408141659632

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

此時客戶端不用重啟, 將自動將新增的流控規則推送到此客戶端中:

image-20210408142410982

快速訪問流控接口:

@GetMapping("testD")
    @SentinelResource(value = "/retaLimit/byUrl",blockHandler = "handler" ,blockHandlerClass = CustomerBlockHandler.class)
    public void testD() {
        System.out.println("業務代碼執行完畢!");
    }

打印信息如下:

業務代碼執行完畢!
業務代碼執行完畢!
業務代碼執行完畢!
方法被流控
方法被流控
方法被流控
方法被流控
業務代碼執行完畢!
方法被流控
方法被流控

說明成功將流控規則從Nacos中拉取下來,並此時重啟客戶端后,流控規則仍然存在,實現持久化.

3. 改造Sentinel-dashboard

在上面的演示中, 我們發現此時的dashboard,僅僅只是變成查看 客戶端 從Nacos中拉取下來的配置,並沒有連接到Nacos中, 所以當我們從dashboard中添加規則時,並沒有將規則持久化到Nacos中, 當我們重啟客戶端后,dashboard 新增的規則仍然消失,

但是如果我們每次新增規則,都要以這樣新增 JSON的方式,又比較麻煩,所以我們可以將dashboard進行改造,使之新增規則時,同樣將規則持久化到Nacos中

首先,需要將dashboard 的源碼下載下來: https://github.com/alibaba/Sentinel/tree/master/sentinel-dashboard (源碼下載較慢的話,可以私信或評論發你),並打開(本人下載的是1.8)

查看源碼中,在controller包中,有幾個特殊的Controller, 對應着頁面中的各個規則的CRUD, 以FlowControllerV1 為例:

image-20210408185522479

查看此類,有一個非常重要的字段:

@Autowired
private SentinelApiClient sentinelApiClient;

每個Controller 就是通過這個對象, 與Sentinel客戶端進行Http交互, 將從頁面上增加,刪除的操作,通過調用對應的API 來操作對應的客戶端;

例如保存規則的方法中:

private CompletableFuture<Void> publishRules(String app, String ip, Integer port) {
        List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
        return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules);
    }

調用了此對象的setFlowRuleOfMachineAsync 方法,一直點進去看,會發現最終發送了一個Http請求,

executeCommand(new HttpGet(urlBuilder.toString()));

那么其他方法,其他各種規則配置類都是一樣, 這樣一來, dashboard 將直接與客戶端請求HTTP請求, 下面我們進行改造,使之 讀取規則從Nacos中讀取,保存也往Nacos中保存,.

開始改造:

在此源碼中,其實已經為我們准備了關於此方面的示例,在test包中,

image-20210408221341777

已經有了關於關聯Nacos的示例, 其中 FlowRuleNacosProvider 類和FlowRuleNacosPublisher 類分別繼承了DynamicRuleProvider接口 和 DynamicRulePublisher 接口, 實現了拉取 和推送的方法, 而這兩個類則可以替換FlowControllerV1 類中sentinelApiClient字段, 將這四個類拷貝到 主包中,創建Nacos文件夾:

image-20210408222032375

注冊類時修Bean的id:

@Component("myFlowRuleNacosProvider")
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {

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

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

@Component("myFlowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {

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

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

並修改NacosConfig 類, 將Nacos的地址改成自己的地址

@Configuration
public class NacosConfig {

    @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 {
        return ConfigFactory.createConfigService("192.168.100.108");
    }
}

並將依賴中,關於nacos持久化的包,test標簽注釋:

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

此時,我們只需將所有controller包中的sentinelApiClient ,換成 對應的 Nacos對象即可,例如上面的保存流控規則:

@RestController
@RequestMapping(value = "/v1/flow")
public class FlowControllerV1 {

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

    @Autowired
    private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;

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

    private void publishRules(/*@NonNull*/ String app) throws Exception {
        List<FlowRuleEntity> rules = repository.findAllByApp(app);
        rulePublisher.publish(app, rules);
    }
}

此時,當我們再保存流控規則時,將調用rulePublisherpublish 方法, 對Nacos進行保存,

但是不建議修改原生的版本,官方也給我們提供了示例,即v2 包中FlowControllerV2類,此時的接口為 "/v2/flow"

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

建議將所有的controller拷貝一份v2版本, 下面就着官方的示例,看如何將頁面上的 菜單也切換到v2的版本上

同樣,對於前端, 也提供了Demo, 在resources/app/scripts/directives/sidebar/sidebar.html 中,修改流控規則的路由,

<li ui-sref-active="active" ng-if="!entry.isGateway">
            <a ui-sref="dashboard.flowV1({app: entry.app})">
              <i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控規則</a>
          </li>

修改為

<a ui-sref="dashboard.flow({app: entry.app})">

路由規則配置在app.js中:

image-20210408223942858

那么此時,當點擊流控規則按鈕時,將跳轉到 flow_v2.html中, 而這個html也是提供好的,調用的接口都是 "v2":

如圖:當我們再次點擊流控規則時,無論是保存還是獲取,都將調用v2的版本,其他頁面也以此類推

image-20210408224116345

同時,對於客戶端,也需要添加指定對應的 dataId 和 GroupId

      datasource:
        dsl:
          nacos:
            server-addr: 192.168.100.109:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data_type: json
            rule-type: flow
        flow: # 和 改造后的對應
            nacos:
                server-addr: 192.168.100.109:8848
                dataId: ${spring.application.name}-flow-rules
                groupId: SENTINEL_GROUP
                data_type: json
                rule-type: flow

上面的介紹中,僅僅只是以流控規則為例, 即FlowControllerV1, 同時,對於Nacos, 也就只創建了FlowRuleNacosProviderFlowRuleNacosPublisher 類, 對於其他 的例如降級規則,系統規則等,都需創建 對應的Nacos替換類, 用於替換相應controller的

sentinelApiClient 字段, 同時前端頁面也是一樣.

還有更簡單的方式,是直接使用阿里雲提供的服務,具體使用,請自行百度或者查看官網:

https://github.com/alibaba/Sentinel/wiki/AHAS-Sentinel-控制台


免責聲明!

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



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