您好,登錄后才能下訂單哦!
在Sentinel控制臺對某個微服務的接口資源配置了流控、降級等規則后,若重啟了該微服務,那么配置的相關規則就會丟失,因為Sentinel默認將規則存放在內存中。每次重啟微服務都得重新配置規則顯然是不合理的,所以我們需要將配置好的規則進行持久化存儲,而Sentinel提供了兩種規則持久化模式:
本小節先介紹一下拉模式(pull),該模式的架構圖如下:
因為需要讀寫本地文件,所以實現拉模式需要編寫一些代碼,首先在項目中添加如下依賴:
<!-- Sentinel Datasource -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-extension</artifactId>
</dependency>
由于Sentinel有好幾種規則,所以需要寫的代碼也有點多,具體代碼如下示例:
package com.zj.node.contentcenter.sentinel;
import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.*;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
/**
* 規則持久化 - 拉模式
*
* @author 01
* @date 2019-08-02
**/
@Slf4j
public class FileDataSourceInitial implements InitFunc {
/**
* 定義并實現各個規則對象的轉換器,用于將json格式的數據轉換為相應的Java對象
*/
private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(
source,
new TypeReference<List<FlowRule>>() {
}
);
private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(
source,
new TypeReference<List<DegradeRule>>() {
}
);
private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(
source,
new TypeReference<List<SystemRule>>() {
}
);
private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject(
source,
new TypeReference<List<AuthorityRule>>() {
}
);
private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject(
source,
new TypeReference<List<ParamFlowRule>>() {
}
);
@Override
public void init() throws Exception {
// 規則持久化文件所存放的路徑及文件名,可以按需求自行修改
String ruleDir = System.getProperty("user.home") + "/sentinel/rules";
String flowRulePath = ruleDir + "/flow-rule.json";
String degradeRulePath = ruleDir + "/degrade-rule.json";
String systemRulePath = ruleDir + "/system-rule.json";
String authorityRulePath = ruleDir + "/authority-rule.json";
String paramFlowRulePath = ruleDir + "/param-flow-rule.json";
// 目錄路徑及文件若不存在則創建
this.mkdirIfNotExits(ruleDir);
this.createFileIfNotExits(flowRulePath);
this.createFileIfNotExits(degradeRulePath);
this.createFileIfNotExits(systemRulePath);
this.createFileIfNotExits(authorityRulePath);
this.createFileIfNotExits(paramFlowRulePath);
// 注冊各個規則的可讀寫數據源
this.registerFlowRWDS(flowRulePath);
this.registerDegradeRWDS(degradeRulePath);
this.registerSystemRWDS(systemRulePath);
this.registerAuthorityRWDS(authorityRulePath);
this.registerParamRWDS(paramFlowRulePath);
}
/**
* 注冊流控規則的可讀寫數據源
*/
private void registerFlowRWDS(String flowRulePath) throws FileNotFoundException {
// 構建可讀數據源,用于定時讀取本地的json文件
ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(
flowRulePath,
flowRuleListParser
);
// 將可讀數據源注冊至FlowRuleManager,當文件里的規則內容發生變化時,就會更新到緩存里
FlowRuleManager.register2Property(flowRuleRDS.getProperty());
// 構建可寫數據源
WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(
flowRulePath,
this::toJson
);
// 將可寫數據源注冊至transport模塊的WritableDataSourceRegistry中
// 這樣收到控制臺推送的規則時,Sentinel會先更新到內存,然后將規則寫入到文件中
WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
}
/**
* 注冊降級規則的可讀寫數據源
*/
private void registerDegradeRWDS(String degradeRulePath) throws FileNotFoundException {
ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(
degradeRulePath,
degradeRuleListParser
);
DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(
degradeRulePath,
this::toJson
);
WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);
}
/**
* 注冊系統規則的可讀寫數據源
*/
private void registerSystemRWDS(String systemRulePath) throws FileNotFoundException {
ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(
systemRulePath,
systemRuleListParser
);
SystemRuleManager.register2Property(systemRuleRDS.getProperty());
WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(
systemRulePath,
this::toJson
);
WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
}
/**
* 注冊授權規則的可讀寫數據源
*/
private void registerAuthorityRWDS(String authorityRulePath) throws FileNotFoundException {
ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(
authorityRulePath,
authorityRuleListParser
);
AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(
authorityRulePath,
this::toJson
);
WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);
}
/**
* 注冊熱點參數規則的可讀寫數據源
*/
private void registerParamRWDS(String paramFlowRulePath) throws FileNotFoundException {
ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(
paramFlowRulePath,
paramFlowRuleListParser
);
ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(
paramFlowRulePath,
this::toJson
);
ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
}
private void mkdirIfNotExits(String filePath) {
File file = new File(filePath);
if (!file.exists()) {
boolean result = file.mkdirs();
log.info("創建目錄: {} filePath: {}", result ? "成功" : "失敗", filePath);
}
}
private void createFileIfNotExits(String filePath) throws IOException {
File file = new File(filePath);
if (!file.exists()) {
boolean result = file.createNewFile();
log.info("創建文件: {} filePath: {}", result ? "成功" : "失敗", filePath);
}
}
private <T> String toJson(T t) {
return JSON.toJSONString(t);
}
}
這里有兩個重要的API:
FileRefreshableDataSource
定時從指定文件中讀取規則JSON文件【上圖中的本地文件】,如果發現文件發生變化,就更新規則緩存FileWritableDataSource
接收控制臺規則推送,并根據配置,修改規則JSON文件【上圖中的本地文件】編寫完以上代碼后,還需要在項目的 resources/META-INF/services
目錄下創建一個文件,名為 com.alibaba.csp.sentinel.init.InitFunc
,如下圖所示:
然后編輯文件內容如下:
# 修改為上面FileDataSourceInitial的包名類名全路徑
com.zj.node.contentcenter.sentinel.FileDataSourceInitial
完成以上步驟后,重啟項目,此時就可以自行測試一下規則是否能持久化存儲了。
拉模式的優缺點:
如果有了解過規則持久化相關配置的小伙伴可能會有疑問,Spring Cloud Alibaba不是提供了如下配置了嗎?為什么要全部自己寫呢?
spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
#spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
#spring.cloud.sentinel.datasource.ds1.file.data-type=custom
#spring.cloud.sentinel.datasource.ds1.file.converter-class=com.alibaba.cloud.examples.JsonFlowRuleListConverter
#spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
關于這個問題,可以查看一下這個Issues
官方文檔:
在上一小節中,我們了解了規則持久化中拉模式的原理及使用方式,本小節將介紹在生產環境中更為常用的推模式(push)。
推模式的架構圖如下:
使用推模式進行規則的持久化還是稍微有些麻煩的,因為需要改動Sentinel控制臺的源碼,對控制臺的改造主要是為了實現:
這里僅演示對流控規則的改造讓其支持推模式的規則持久化,因為其他規則的改造過程也是類似的,稍微琢磨一下就可以了。首先需要下載Sentinel的源碼包,我這里使用的是1.6.3版本:
下載并解壓完成后,使用IDE打開sentinel-dashboard這個項目,如下:
第一步:修改該項目的pom.xml文件,找到如下依賴項:
<!-- for Nacos rule publisher sample -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<scope>test</scope>
</dependency>
將<scope>test</scope>
一行注釋掉,即修改為如下:
<!-- for Nacos rule publisher sample -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<!-- <scope>test</scope> -->
</dependency>
第二步:找到 sentinel-dashboard/src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacos
目錄,將整個目錄拷貝到 sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos
下,如下圖所示:
拷貝完成后rule包結構如下圖:
第三步:修改流控規則Controller,到com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2
類的源碼中找到這一段:
@Autowired
@Qualifier("flowRuleDefaultProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleDefaultPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
修改@Qualifier
注解的內容,將其修改為:
@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
第四步:打開sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html
文件,找到一段被注釋的代碼,如下:
<!--<li ui-sref-active="active" ng-if="entry.appType==0">-->
<!--<a ui-sref="dashboard.flow({app: entry.app})">-->
<!--<i class="glyphicon glyphicon-filter"></i> 流控規則 V1</a>-->
<!--</li>-->
只需要把注釋解開,即改為:
<li ui-sref-active="active" ng-if="entry.appType==0">
<a ui-sref="dashboard.flow({app: entry.app})">
<i class="glyphicon glyphicon-filter"></i> 流控規則 V1</a>
</li>
到這步為止,我們就對sentinel-dashboard源碼改造完畢了,現在流控規則就可以支持推模式的持久化了,接下來就是編譯、啟動以及測試。
打開idea的terminal,執行如下命令進行打包編譯:
mvn clean package -DskipTests
然后進入target目錄,使用如下命令執行jar包,啟動Sentinel控制臺:
java -jar sentinel-dashboard.jar
注:也可以選擇直接在idea中點擊啟動按鈕來啟動Sentinel控制臺,效果是一樣的
啟動完成后,使用瀏覽器打開,可以看到Sentinel的菜單欄中比之前多出了一項流控規則 V1:
注:若沒有顯示該項,可以嘗試清除瀏覽器緩存或換個瀏覽器打開
改造完控制臺后,接下來開始改造客戶端,首先在項目中添加如下依賴:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
然后添加各個規則配置:
spring:
cloud:
sentinel:
datasource:
# 名稱隨意
flow:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-flow-rules
groupId: SENTINEL_GROUP
# 規則類型,取值見:
# org.springframework.cloud.alibaba.sentinel.datasource.RuleType
rule-type: flow
degrade:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
rule-type: degrade
system:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-system-rules
groupId: SENTINEL_GROUP
rule-type: system
authority:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-authority-rules
groupId: SENTINEL_GROUP
rule-type: authority
param-flow:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-param-flow-rules
groupId: SENTINEL_GROUP
rule-type: param-flow
完成以上步驟后重啟項目,然后回到Sentinel控制臺里的流控規則 V1中新增流控規則,之所以不在簇點鏈路中添加,是因為簇點鏈路中的按鈕依舊是調用之前的邏輯添加到內存中。新增流控規則如下:
新增完成后,到Nacos Server的配置列表上,可以看到該規則的配置數據,證明已經持久化存儲到Nacos了:
若直接在Nacos上修改流控規則,然后刷新Sentinel控制臺,控制臺上的顯示也會被修改
此時重啟Sentinel控制臺和微服務,然后刷新控制臺,可以發現該流控規則依舊存在:
以上折騰了那么多只實現了流控規則的持久化,這還是因為官方準備好了示例代碼。Sentinel有若干種規則,例如降級規則、系統規則、授權規則、熱點規則等,都需要使用類似的方式,修改 com.alibaba.csp.sentinel.dashboard.controller
包中對應的Controller,才能實現持久化,所以本小節僅是拋磚引玉,其他規則可以自行動手參考著實現。
推模式優缺點:
官方文檔:
在生產環境使用Sentinel是必須要實現規則持久化的,而通過以上兩個小節的學習,我們可以得知不管使用哪個模式都需要進行相應的改動,其中想要實現貼近生產使用的推模式需要改動的地方更多更麻煩。
如果不想做這些麻煩的改動,又希望在生產環境使用Sentinel的話,則需要考慮使用阿里云提供的在線托管Sentinel控制臺(AHAS),該在線Sentinel控制臺實現了推模式的規則持久化并可用于生產:
接下來演示一下如何使用這個在線的Sentinel控制臺,根據開通說明文檔注冊了阿里云賬戶后,進入開通頁面:
根據提示開通完成后,進入管理控制臺,點擊接入應用流控:
進入應用接入界面后可以選擇不同的應用接入,這里按照Spring Boot應用接入的說明完成相應步驟:
需要說明一下的是,第二步中的HTTP接口埋點和普通接口埋點都可以省略掉,因為spring-cloud-starter-alibaba-sentinel
依賴包里已經實現了,但需要排除該依賴中的sentinel-transport-simple-http
模塊,避免連接了本地的Sentinel控制臺,即修改依賴如下并添加AHAS Client依賴:
<!-- Sentinel -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<!-- 排除該模塊的目的是不與本地的Sentinel控制臺進行通信,以免造成不必要的干擾 -->
<exclusions>
<exclusion>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- ahas client -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>spring-boot-starter-ahas-sentinel-client</artifactId>
<version>1.3.3</version>
</dependency>
除了修改依賴以外,還需要將配置文件中關于Sentinel控制臺的配置都注釋掉,因為此時我們連接的是在線的Sentinel控制臺。如下:
然后只需要添加AHAS的啟動參數:
ahas:
license: xxxxxxxxx
namespace: default
project:
name: ${spring.application.name}
完成以上步驟后,重啟項目并訪問該項目的接口,應用正常接入的情況下可以在阿里云的控制臺中看到該應用的展示,如下:
點擊該應用就可以進入到Sentinel控制臺,可以看到這里基本上和我們自己搭建的Sentinel控制臺是差不多的,同樣支持實時監控、查看簇點鏈路及配置各種規則:
例如流控規則的添加也是一樣的,只是界面稍微好看一點而已:
至此就完成將應用接入AHAS了,由于操作與Sentinel控制臺基本一樣這里就不展開介紹了,可以自行測試搗鼓一下,反正可視化的頁面使用起來還是比較容易的。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。