在之前的練習中,只要應用重啟,就需要重新配置,這樣在我們實際的專案是非常不實用的,那麼有沒有辦法把我們配置的規則儲存下來呢?答案是YES,那麼接下來,給大家來介紹如何將Sentinel規則持久化。
Document: 傳送門
- File Datasource(檔案儲存)
- Pull 模式
- Push 模式
- Nacos configuration
- Apollo
File Datasource
Pull 模式
原理:
擴充套件寫資料來源(WritableDataSource
), 客戶端主動向某個規則管理中心定期輪詢拉取規則,這個規則中心可以是 RDBMS、檔案 等
pull 模式的資料來源(如本地檔案、RDBMS 等)一般是可寫入的。使用時需要在客戶端註冊資料來源:將對應的讀資料來源註冊至對應的 RuleManager,將寫資料來源註冊至 transport 的WritableDataSourceRegistry
中。
過程如下:
Pull Demo
Step 1: 新增配置
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-extension</artifactId> </dependency>
Step 2: 編寫持久化程式碼,實現
com.alibaba.csp.sentinel.init.InitFunc
- 程式碼參考自:傳送門
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 java.io.File; import java.io.IOException; import java.util.List; /** * FileDataSourceInit for : 自定義Sentinel儲存檔案資料來源載入類 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> * @since 2019/7/21 */ public class FileDataSourceInit implements InitFunc { @Override public void init() throws Exception { // TIPS: 如果你對這個路徑不喜歡,可修改為你喜歡的路徑 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 hotParamFlowRulePath = ruleDir + "/param-flow-rule.json"; this.mkdirIfNotExits(ruleDir); this.createFileIfNotExits(flowRulePath); this.createFileIfNotExits(degradeRulePath); this.createFileIfNotExits(systemRulePath); this.createFileIfNotExits(authorityRulePath); this.createFileIfNotExits(hotParamFlowRulePath); // 流控規則 ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>( flowRulePath, flowRuleListParser ); // 將可讀資料來源註冊至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, degradeRuleListParser ); DegradeRuleManager.register2Property(degradeRuleRDS.getProperty()); WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>( degradeRulePath, this::encodeJson ); WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS); // 系統規則 ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>( systemRulePath, systemRuleListParser ); SystemRuleManager.register2Property(systemRuleRDS.getProperty()); WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>( systemRulePath, this::encodeJson ); WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS); // 授權規則 ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>( flowRulePath, authorityRuleListParser ); AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty()); WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>( authorityRulePath, this::encodeJson ); WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS); // 熱點引數規則 ReadableDataSource<String, List<ParamFlowRule>> hotParamFlowRuleRDS = new FileRefreshableDataSource<>( hotParamFlowRulePath, hotParamFlowRuleListParser ); ParamFlowRuleManager.register2Property(hotParamFlowRuleRDS.getProperty()); WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>( hotParamFlowRulePath, this::encodeJson ); ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS); } /** * 流控規則物件轉換 */ 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>> hotParamFlowRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<ParamFlowRule>>() { } ); /** * 建立目錄 * * @param filePath */ private void mkdirIfNotExits(String filePath) { File file = new File(filePath); if (!file.exists()) { file.mkdirs(); } } /** * 建立檔案 * * @param filePath * @throws IOException */ private void createFileIfNotExits(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { file.createNewFile(); } } private <T> String encodeJson(T t) { return JSON.toJSONString(t); } }
Step 3: 啟用上述程式碼
resource 目錄下建立
resources/META-INF/services
目錄並建立檔案com.alibaba.csp.sentinel.init.InitFunc
,內容為:com.sxzhongf.sharedcenter.configuration.sentinel.datasource.FileDataSourceInit
Pull 優缺點
- 優點
- 簡單,無任何依賴
- 沒有額外依賴
- 缺點
- 不保證一致性(規則是使用
FileRefreshableDataSource
定時更新,會有延遲) - 實時性不保證(規則是使用
FileRefreshableDataSource
定時更新) - 拉取過於頻繁也可能會有效能問題
- 由於檔案儲存於本地,容易丟失
- 不保證一致性(規則是使用
- 參考資料:
Push 模式
推薦通過控制檯設定規則後將規則推送到統一的規則中心,客戶端實現
ReadableDataSource
介面端監聽規則中心實時獲取變更,流程如下:
實現原理
- 控制檯推送規則到Nacos/遠端配置中心
- Sentinel client 艦艇Nacos配置變化,更新本地快取
shared_center service 加工
- 新增依賴
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>
- 新增配置
spring: cloud: sentinel: datasource: sxzhongf_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 sxzhongf_degrade: nacos: server-addr: localhost:8848 dataId: ${spring.application.name}-degrade-rules groupId: SENTINEL_GROUP rule-type: degrade
Sentinel dashboard 加工
Dashboard 規則改造主要通過2個介面:
com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider
&com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher
Download Sentinel Source Code
修改原
sentinel-dashboard
專案下的POM檔案<!-- for Nacos rule publisher sample --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> <!--註釋掉原檔案中的scope,讓其不僅在test的時候生效--> <!--<scope>test</scope>--> </dependency>
偷懶模式:複製
sentinel-dashboard
專案下test下的nacos包(src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacos
到src/main/java/com/alibaba/csp/sentinel/dashboard/rule
下修改controller中的預設provider & publisher
com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2
中@Autowired // @Qualifier("flowRuleDefaultProvider") @Qualifier("flowRuleNacosProvider") private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider; @Autowired // @Qualifier("flowRuleDefaultPublisher") @Qualifier("flowRuleNacosPublisher") private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
開啟
/Sentinel-1.6.2/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html
檔案,修改程式碼:<!--<li ui-sref-active="active">--> <!--<a ui-sref="dashboard.flow({app: entry.app})">--> <!--<i class="glyphicon glyphicon-filter"></i> 流控規則 V1</a>--> <!--</li>--> --- 改為 <li ui-sref-active="active"> <a ui-sref="dashboard.flow({app: entry.app})"> <i class="glyphicon glyphicon-filter"></i> NACOS 流控規則 V1</a> </li>
Dashboard中要修改的程式碼已經好了。
重新啟動 Sentinel-dashboard
mvn clean package -DskipTests
測試效果
Sentinel 新增流控規則:
Nacos 檢視同步的配置: