文章目錄
- 推送模式
- 本地文件持久化(拉模式)
- 配置yml
- 編寫處理類
- 添加配置
- 演示
- 配置中心持久化(推模式)
- 修改nacos在sentinel中生效
- 引入依賴
- 配置文件
- 修改sentinel在nacos中生效
- 下載源碼
- 更改代碼
- 演示
- 總結
推送模式
Sentinel 規則的推送有下面三種模式:
通過前面的講解,我們已經知道,可以通過 Dashboard 來為每個 Sentinel 客戶端設置各種各樣的規則,這種屬于原始模式。這種模式存在一個問題,就是這些規則默認是存放在內存中的,極不穩定,所以需要將其持久化。
為了達到持久化的目標,我們需要進行改造,改造的方案有兩種:本地文件持久化(拉模式)、配置中心持久化(推模式)
本地文件持久化(拉模式)
拉模式又被稱為 pull 模式,它的數據源(如本地文件、RDBMS等)一般是可寫入的。本地文件數據源會定時輪詢文件的變更,讀取規則。這樣我們既可以在應用本地直接修改文件來更新規則,也可以通過 Sentinel 控制臺推送規則。以本地文件數據源為例,推送過程如下圖所示:
首先 Sentinel 控制臺通過API將規則推送至客戶端并更新到內存中,接著注冊的寫數據源會將新的規則保存到本地的文件中。使用 pull模式的數據源時一般不需要對Sentinel控制臺進行改造。這種實現方法好處是簡單,壞處是無法保證監控數據的一致性。
配置yml
#數據庫配置
spring:cloud:sentinel:eager: truetransport:port: 9998 #跟控制臺交流的端口,隨意指定一個未使用的端口即可dashboard: localhost:8080 #指定控制臺服務的地址filter:enabled: false
編寫處理類
實現 InitFunc 接口,在 init 中處理 DataSource 初始化邏輯,并利用 SPI 機制實現加載。
public class FilePersistence implements InitFunc {@Value("${spring.application.name}")private String applicationName;@Overridepublic void init() throws Exception {//創建規則文件String ruleDir = System.getProperty("user.home") + "/sentinel-rules/" + applicationName;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);//流控規則//創建流控規則的可讀數據源ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(flowRulePath,source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>(){}));//將可讀數據源注冊至 FlowRuleManager,這樣當規則文件發生變化時,就會更新規則到內存FlowRuleManager.register2Property(flowRuleRDS.getProperty());WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(flowRulePath,this::encodeJson);//將可寫數據源注冊至 transport 模塊的 WritableDataSourceRegistry 中.//這樣收到控制臺推送的規則時,Sentinel 會先更新到內存,然后將規則寫入到文件中.WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);//降級規則ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(degradeRulePath,source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>(){}));DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(degradeRulePath,this::encodeJson);WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);//系統規則ReadableDataSource<String, List<SystemRule>> systemRuleRDS= new FileRefreshableDataSource<>(systemRulePath,source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>(){}));SystemRuleManager.register2Property(systemRuleRDS.getProperty());WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(systemRulePath,this::encodeJson);WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);//授權規則ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(authorityRulePath,source-> JSON.parseObject(source, new TypeReference<List<AuthorityRule>>(){}));AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(authorityRulePath, this::encodeJson);WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);//熱點參數規則ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(paramFlowRulePath,source-> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>(){}));ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(paramFlowRulePath,this::encodeJson);ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);}
}
- FileRefreshableDataSource:每次更新規則時自動讀取持久化文件更新到map緩存。
- FileWritableDataSource:寫數據源,將 sentinel 控制臺發送過來的規則信息寫到持久化文件中。在客戶端的socket接收到規則信息后,更新緩存的時候也會將規則信息寫入文件中持久化。
添加配置
在resources下創建配置目錄 META-INF/services
,然后添加文件com.alibaba.csp.sentinel.init.InitFunc
,在文件中添加配置類的全路徑it.aq.cheetah.config.FilePersistence
。
這樣當在 Dashboard 中修改了配置后,Dashboard 會調用客戶端的接口修改客戶端內存中的值,同時將配置寫入文件中,這樣操作的話規則是實時生效的,如果是直接修改文件中的內容,這樣需要等定時任務3秒后執行才能讀到最新的規則。接下來我們演示下:
演示
編寫測試類
@RestController
@RequestMapping("/product2")
@Slf4j
public class ProductController2 {@RequestMapping("/test")@SentinelResource(value = "test")public String test() {return "product2";}
}
啟動項目,發現在目錄下生成了空的規則文件
在頁面上增加流控規則
然后去看文件flow-rule.json
,發現存到了本地文件中
接著我們仿照該規則仿寫一個熔斷規則,然后查看網頁數據確實生效了
配置中心持久化(推模式)
推模式又叫 Push 模式,它是通過注冊中心實現的,Sentinel控制臺——>配置中心——>Sentinel數據源——>Sentinel
用戶不僅可以通過sentinel控制臺進行更新,也可以通過nacos配置中心進行更新,所以在sentinel控制臺或nacos中修改規則后,都需要通知對方刷新最新的配置。
修改nacos在sentinel中生效
引入依賴
我們在之前項目的基礎上引入新的依賴
<!--nacos配置中心-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--以nacos作為sentinel數據源的依賴--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId></dependency>
配置文件
nacos 配置:因為我們用nacos作為了配置中心,我們可以將sentinel的基本配置放入到nacos中就可以了,所以當前服務的yml配置文件中只需要寫一些基本的配置就可以了。
spring:cloud:nacos:discovery:server-addr: localhost:8848config:server-addr: localhost:8848file-extension: yml
在nacos中配置sentinel信息
spring: cloud:sentinel:transport:# 跟控制臺交流的端口,隨意指定一個未使用的端口即可port: 9998 # 指定控制臺服務的地址dashboard: localhost:8080 # sentinel用nacos作為數據源的配置datasource: #流控管理(這個名稱可以自定義)flow-control: # 告訴sentinel用nacos作為數據源nacos: # 配置中心里執行文件的 dataIddataId: shop-product-flow.json # nacos的地址serverAddr: 127.0.0.1:8848 # 指定文件配置的是哪種規則rule-type: flow
注意:如果使用的 namespace 不是默認的,記得配置 namespace 參數。
- dataId:需要告訴 sentinel 讀取配置中心中的哪個配置文件;
- rule-type:告訴 sentinel 配置文件配置的控制規則,flow:流控、degrade:熔斷、param-flow 熱點參數,想看有哪些規則參數可以查看
com.alibaba.cloud.sentinel.datasource
包下的枚舉類:RuleType。
public enum RuleType {/*** flow.*/FLOW("flow", FlowRule.class),/*** degrade.*/DEGRADE("degrade", DegradeRule.class),/*** param flow.*/PARAM_FLOW("param-flow", ParamFlowRule.class),/*** system.*/SYSTEM("system", SystemRule.class),/*** authority.*/AUTHORITY("authority", AuthorityRule.class),/*** gateway flow.*/GW_FLOW("gw-flow","com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),/*** api.*/GW_API_GROUP("gw-api-group","com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
shop-product-flow.json
文件中配置【流控規則】
[{"clusterConfig": {"acquireRefuseStrategy": 0,"clientOfflineTime": 2000,"fallbackToLocalWhenFail": true,"resourceTimeout": 2000,"resourceTimeoutStrategy": 0,"sampleCount": 10,"strategy": 0,"thresholdType": 0,"windowIntervalMs": 1000},"clusterMode": false,"controlBehavior": 0,"count": 10.0,"grade": 1,"limitApp": "default","maxQueueingTimeMs": 500,"resource": "/product2/test","strategy": 0,"warmUpPeriodSec": 10}
]
然后去 dashboard 中查看,發現流控規則已經在控制中顯示了
目前我們已經實現了在 nacos 中配置的文件直接在sentinel dashboard
中生效,但是我們在sentinel dashboard
中修改了配置,nacos 是不會監聽到并進行修改的。接下來我們實現一下通過 sentinel 控制臺設置的規則直接持久化到 nacos配置中心。
修改sentinel在nacos中生效
Sentinel 控制臺提供 DynamicRulePublisher
和 DynamicRuleProvider
接口用于實現應用維度的規則推送和拉取。
下載源碼
https://github.com/alibaba/Sentinel/releases
下載dashboard的代碼源碼。
解壓之后打開sentinel-dashboard
項目,將 pom.xml 文件中作用域為 test 的注釋掉,注釋掉后默認的作用域為 compile。
- test:作用域表示該依賴項只在測試時有用,在編譯和運行時不會被用到。
- compile:作用域范圍的依賴項在所有情況下都是有效的,包括編譯、運行和測試。
把 test 包下的兩個類復制過來
NacosConfigUtil
類主要就是 nacos 配置的規則,比如配置文件的后綴,分組Group_ID等等。因為我用的分組是默認分組,所以改為DEFAULT_GROUP
,我之前的規則文件是shop-product-flow.json
,所以我把規則文件后綴FLOW_DATA_ID_POSTFIX
改為"-flow.json"。NacosConfig
類是為了注入nacos的信息以及轉換器類。
更改代碼
application.properties
中增加 nacos 的配置
# nacos 配置
nacos.serverAddr=localhost:8848
nacos.username=nacos
nacos.password=nacos
NacosConfig
修改為從配置文件中獲取nacos配置
@Beanpublic ConfigService nacosConfigService() throws Exception {Properties properties = new Properties();//Nacos地址properties.put("serverAddr", serverAddr);//Nacos用戶名properties.put("username", username);//Nacos密碼properties.put("password", password);return ConfigFactory.createConfigService(properties);}
在com.alibaba.csp.sentinel.dashboard.rule.FlowRuleApiPublisher#publish
方法中增加推送到nacos的邏輯代碼
//將規則推送到nacos
configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, converter.convert(rules));
在com.alibaba.csp.sentinel.dashboard.rule.FlowRuleApiProvider#getRules
方法中修改為從nacos中讀取配置的邏輯
@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);
}
改造流控的controller類FlowControllerV1,將配置保存到內存中的邏輯改為保存到nacos中
@Autowired
@Qualifier("flowRuleDefaultProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;@Autowired
@Qualifier("flowRuleDefaultPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;@GetMapping("/rules")
@AuthAction(PrivilegeType.READ_RULE)
public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app,@RequestParam String ip,@RequestParam Integer port) {......try {
// List<FlowRuleEntity> rules = sentinelApiClient.fetchFlowRuleOfMachine(app, ip, port);//從nacos中讀取規則List<FlowRuleEntity> rules = ruleProvider.getRules(app);rules = repository.saveAll(rules);return Result.ofSuccess(rules);} catch (Throwable throwable) {logger.error("Error when querying flow rules", throwable);return Result.ofThrowable(-1, throwable);}
}private void publishRules(String app, String ip, Integer port) throws Exception {//將規則推送到nacosList<FlowRuleEntity> rules = repository.findAllByApp(app);rulePublisher.publish(app, rules);// List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
// return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules);
}//其余調用publishRules方法的地方做下簡單調整
演示
啟動當前項目,流控規則中存在我們之前在nacos中創建的文件,我們將原來的單機閾值從10改為12,然后保存。查看nacos中配置文件的數據,發現已經生效了。
至于其他規則,大家可以自行實現,此處就不一一實現了
總結
到這兒,服務容錯中間件Sentinel的兩種持久化模式就已經介紹完了。下一篇將為大家帶來Feign整合容錯組件 Sentinel 的文章,敬請期待吧!
后續的文章,我們將繼續完善我們的微服務系統,集成更多的Alibaba組件。想要了解更多JAVA后端知識,請點擊文末名片與我交流吧。留下您的一鍵三連,讓我們在這個寒冷的東西互相溫暖吧!
參考鏈接:
- https://blog.csdn.net/weixin_36279234/article/details/130922604;
- https://blog.csdn.net/u022812849/article/details/131206976;