在Sentinel控制台中配置的規則,默認是保存在內存中的,重啟后就會丟失;本文主要介紹規則的持久化,文中使用到的軟件版本:Sentinel 1.3.2、Spring Boot 2.2.5.RELEASE、Spring Cloud Hoxton.SR3、Java 1.8.0_191。
1、規則管理及推送
推送模式 | 說明 | 優點 | 缺點 |
---|---|---|---|
原始模式 | API 將規則推送至客戶端並直接更新到內存中,擴展寫數據源(WritableDataSource ) |
簡單,無任何依賴 | 不保證一致性;規則保存在內存中,重啟即消失。嚴重不建議用於生產環境 |
Pull 模式 | 擴展寫數據源(WritableDataSource ), 客戶端主動向某個規則管理中心定期輪詢拉取規則,這個規則中心可以是 RDBMS、文件 等 |
簡單,無任何依賴;規則持久化 | 不保證一致性;實時性不保證,拉取過於頻繁也可能會有性能問題。 |
Push 模式 | 擴展讀數據源(ReadableDataSource ),規則中心統一推送,客戶端通過注冊監聽器的方式時刻監聽變化,比如使用 Nacos、Zookeeper 等配置中心。這種方式有更好的實時性和一致性保證。生產環境下一般采用 push 模式的數據源。 |
規則持久化;一致性;快速 | 引入第三方依賴 |
1.1、原始模式
如果不做任何修改,Dashboard 的推送規則方式是通過 API 將規則推送至客戶端並直接更新到內存中:
這種做法的好處是簡單,無依賴;壞處是應用重啟規則就會消失,僅用於簡單測試,不能用於生產環境。
1.2、Pull模式
pull 模式的數據源(如本地文件、RDBMS 等)一般是可寫入的。使用時需要在客戶端注冊數據源:將對應的讀數據源注冊至對應的 RuleManager,將寫數據源注冊至 transport 的 WritableDataSourceRegistry 中。本地文件數據源會定時輪詢文件的變更,讀取規則。這樣我們既可以在應用本地直接修改文件來更新規則,也可以通過 Sentinel 控制台推送規則。以本地文件數據源為例,推送過程如下圖所示:
使用 pull 模式的數據源時一般不需要對 Sentinel 控制台進行改造。這種實現方法好處是簡單,不引入新的依賴,壞處是無法保證監控數據的一致性。
1.3、Push模式
生產環境下一般更常用的是 push 模式的數據源。對於 push 模式的數據源,如遠程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不應由 Sentinel 客戶端進行,而應該經控制台統一進行管理,直接進行推送,數據源僅負責獲取配置中心推送的配置並更新到本地。因此推送規則正確做法應該是 配置中心控制台/Sentinel 控制台 → 配置中心 → Sentinel 數據源 → Sentinel,而不是經 Sentinel 數據源推送至配置中心。
2、規則持久化
2.1、Pull模式持久化
該模式只需要在應用中進行改造,不需要改造sentinel控制台。
2.1.1、引入依賴
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-extension</artifactId> <version>1.8.0</version> </dependency>
2.1.2、編寫持久化類
package com.inspur.scdemo.server.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.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; /** * 文件數據源 */ public class FileDataSourceInitFunc implements InitFunc { private ObjectMapper objectMapper = new ObjectMapper(); /**流控規則對象轉換*/ private Converter<String, List<FlowRule>> flowRuleConverter = source -> { try { return objectMapper.readValue(source, new TypeReference<List<FlowRule>>(){}); } catch (JsonProcessingException e) { e.printStackTrace(); } return null; }; /**降級規則對象轉換*/ private Converter<String, List<DegradeRule>> degradeRuleConverter = source -> { try { return objectMapper.readValue(source, new TypeReference<List<DegradeRule>>(){}); } catch (JsonProcessingException e) { e.printStackTrace(); } return null; }; /**系統規則對象轉換*/ private Converter<String, List<SystemRule>> systemRuleConverter = source -> { try { return objectMapper.readValue(source, new TypeReference<List<SystemRule>>(){}); } catch (JsonProcessingException e) { e.printStackTrace(); } return null; }; /**授權規則對象轉換*/ private Converter<String, List<AuthorityRule>> authorityRuleConverter = source -> { try { return objectMapper.readValue(source, new TypeReference<List<AuthorityRule>>(){}); } catch (JsonProcessingException e) { e.printStackTrace(); } return null; }; /**授權規則對象轉換*/ private Converter<String, List<ParamFlowRule>> paramFlowRuleConverter = source -> { try { return objectMapper.readValue(source, new TypeReference<List<ParamFlowRule>>(){}); } catch (JsonProcessingException e) { e.printStackTrace(); } return null; }; @Override public void init() throws Exception { String ruleDir = "d:/temp/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"; //流控規則 ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(flowRulePath, flowRuleConverter); FlowRuleManager.register2Property(flowRuleRDS.getProperty()); WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(flowRulePath, this::encodeJson); WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS); //降級規則 ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(degradeRulePath, degradeRuleConverter); DegradeRuleManager.register2Property(degradeRuleRDS.getProperty()); WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(degradeRulePath, this::encodeJson); WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS); //系統規則 ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(systemRulePath, systemRuleConverter); SystemRuleManager.register2Property(systemRuleRDS.getProperty()); WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(systemRulePath, this::encodeJson); WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS); //授權規則 ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(flowRulePath, authorityRuleConverter); AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty()); WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(authorityRulePath, this::encodeJson); WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS); //熱點參數規則 ReadableDataSource<String, List<ParamFlowRule>> hotParamFlowRuleRDS = new FileRefreshableDataSource<>(paramFlowRulePath,paramFlowRuleConverter); ParamFlowRuleManager.register2Property(hotParamFlowRuleRDS.getProperty()); WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(paramFlowRulePath,this::encodeJson); ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS); } private <T> String encodeJson(T t) { try { return objectMapper.writeValueAsString(t); } catch (JsonProcessingException e) { e.printStackTrace(); } return null; } }
2.1.3、啟用持久化類
資源目錄(通常是resource
目錄)創建META-INF/services
目錄,並在該目錄下創建com.alibaba.csp.sentinel.init.InitFunc
文件,內容為:
com.inspur.scdemo.server.sentinel.FileDataSourceInitFunc
2.1.3、驗證
啟動sentinel控制台並啟動應用,配置規則后,可以看到生成了對應的文件,文件內容就是規則信息:
2.2、Push模式持久化
該模式需同時改造sentinel控制台和自己的應用。
2.2.1、控制台改造
2.2.1.1、下載sentinel源碼
https://github.com/alibaba/Sentinel
2.2.1.2、修改原sentinel-dashboard項目下的POM文件
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> <!--scope>test</scope--> </dependency>
注釋掉scope
2.2.1.3、復制sentinel-dashboard項目下test中的nacos代碼
src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacos到src/main/java/com/alibaba/csp/sentinel/dashboard/rule下
2.2.1.4、修改NacosConfig中的nacos服務地址
com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfig:
@Bean public ConfigService nacosConfigService() throws Exception { return ConfigFactory.createConfigService("localhost:8848"); }
2.2.1.5、修改FlowControllerV2中的ruleProvider和rulePublisher
com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2:
@Autowired @Qualifier("flowRuleDefaultProvider") private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider; @Autowired @Qualifier("flowRuleDefaultPublisher") private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
改為:
@Autowired @Qualifier("flowRuleNacosProvider") private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider; @Autowired @Qualifier("flowRuleNacosPublisher") private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
2.2.1.6、sidebar.html流控規則路由從dashboard.flowV1改成dashboard.flow
sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html:
<li ui-sref-active="active" ng-if="!entry.isGateway"> <a ui-sref="dashboard.flow({app: entry.app})"> <i class="glyphicon glyphicon-filter"></i> 流控規則</a> </li>
注意:在該頁面添加規則與在簇點鏈路頁面添加流控規則不是同一頁面,簇點鏈路頁面添加規則需另行改造。
2.2.1.7、其他規則改造
上面的步驟只是改造了流控規則,其他的規則可用參考流控規則進行改造。
2.2.2、應用改造
2.2.2.1、引入依賴
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> <version>1.8.0</version> </dependency>
2.2.2.2、增加規則數據源配置
spring:
cloud:
sentinel:
transport:
port: 8719
dashboard: 10.49.196.10:8080
datasource:
flow:
nacos:
server-addr: 10.49.196.10:8848
dataId: ${spring.application.name}-flow-rules
groupId: SENTINEL_GROUP
rule-type: flow
degrade:
nacos:
server-addr: 10.49.196.10:8848
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
rule-type: degrade
這邊只配置了流控及降級的數據源,其他規則類似配置。
2.2.3、驗證
啟動nacos、sentinel控制台及應用,在sentinel配置規則后,在nacos控制台中可以看到對應的配置,配置內容就是規則信息: