在前面的示例中,對於Sentinel的限流和熔斷的規則都是經過硬編碼實現的,在實際的開發過程當中,咱們都會選擇外部配置的方式來定製規則。Sentinel爲咱們提供了sentinel-datasource-extension來實現規則的外部配置化,並能實現熱更新。redis
首先咱們須要引入對應的依賴包json
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-extension</artifactId> <version>1.8.0</version> </dependency>
該依賴包中源文件總共也就9個,其關係以下所示app
其中的FileRefreshableDataSource可供咱們讀取外部的配置文件,並對文件的更新作監控。那麼在代碼中咱們應該怎麼使用呢?ide
public class SentinelRuleConfiguration implements InitializingBean { private final AtomicBoolean initial = new AtomicBoolean(false) ; private Logger log = LoggerFactory.getLogger(SentinelRuleConfiguration.class) ; @Override public void afterPropertiesSet() throws Exception { if(initial.compareAndSet(false,true)){ log.info("staring to initialize sentinel rule"); try{ flowRule() ; }catch (Exception e){} try{ degradeRule() ; }catch (Exception e){} //添加事件監聽 addEventObserver() ; } } /** * 格式: * [ * { * "resource": "helloworld", * "controlBehavior": 2, * "count": 5, * "grade": 1, * "limitApp": "default", * "strategy": 0 * } * ] * */ private void flowRule() throws FileNotFoundException { // 保存了限流規則的文件的地址 String flowRuleName = "flow-rule.json"; //獲取文件 File file = this.getClassPathFile(flowRuleName) ; if(file == null){ return ; } //定義用於進行數據轉換的對象 Converter<String, List<FlowRule>> converter = new Converter<String, List<FlowRule>>(){ /** * 將讀取到的JSON數據轉換爲對應的對象 * @param source 從數據源(本例是文件)讀取到的數據 * */ @Override public List<FlowRule> convert(String source) { if(StringUtils.isEmpty(source)){ return new ArrayList<FlowRule>() ; } ObjectMapper objectMapper = new ObjectMapper() ; try { List<FlowRule> rules = objectMapper.readValue(source, new TypeReference<List<FlowRule>>(){}) ; if(rules != null && rules.size() > 0){ log.info("sentinel flow rule :{}", objectMapper.writeValueAsString(rules)); } return rules ; } catch (IOException e) { log.error("解析流量控制規則文件失敗,{}",e.getMessage()); } return new ArrayList<FlowRule>() ; } } ; // 建立文件規則數據源 FileRefreshableDataSource<List<FlowRule>> flowRuleDataSource = new FileRefreshableDataSource<List<FlowRule>>(file, converter); // 將Property註冊到 RuleManager 中去 FlowRuleManager.register2Property(flowRuleDataSource.getProperty()); } private File getClassPathFile(String fileName) { try{ return ResourceUtils.getFile("classpath:" + fileName) ; }catch (FileNotFoundException e){ log.warn("can't find file {} in classpath",fileName); } return null ; } private void degradeRule() throws FileNotFoundException { // 保存了熔斷規則的文件的地址 String degradeRuleRuleName = "degrade-rule.json"; //獲取文件 File file = this.getClassPathFile(degradeRuleRuleName) ; if(file == null){ return ; } //定義用於進行數據轉換的對象 Converter<String, List<DegradeRule>> converter = new Converter<String, List<DegradeRule>>(){ /** * 將讀取到的JSON數據轉換爲對應的對象 * @param source 從數據源(本例是文件)讀取到的數據 * */ @Override public List<DegradeRule> convert(String source) { if(StringUtils.isEmpty(source)){ return new ArrayList<DegradeRule>() ; } ObjectMapper objectMapper = new ObjectMapper() ; try { List<DegradeRule> rules = objectMapper.readValue(source, new TypeReference<List<DegradeRule>>(){}) ; if(rules != null && rules.size() > 0){ log.info("sentinel degrade rule :{}", objectMapper.writeValueAsString(rules)); } return rules ; } catch (IOException e) { log.error("解析熔斷控制規則文件失敗,{}",e.getMessage()); } return new ArrayList<DegradeRule>() ; } } ; // 建立文件規則數據源 FileRefreshableDataSource<List<DegradeRule>> degradeRuleDataSource = new FileRefreshableDataSource<List<DegradeRule>>(file, converter); // 將Property註冊到 DegradeRuleManager 中去 DegradeRuleManager.register2Property(degradeRuleDataSource.getProperty()); } private void addEventObserver(){ //熔斷器事件監聽 EventObserverRegistry.getInstance().addStateChangeObserver("logging", (prevState, newState, rule, snapshotValue) -> { if (newState == CircuitBreaker.State.OPEN) { // 變換至 OPEN state 時會攜帶觸發時的值 log.info("{} -> OPEN at {},snapshotValue={}",prevState.name() ,TimeUtil.currentTimeMillis(),snapshotValue); } else { log.info("{} -> {} at {}",prevState.name(), newState.name(), TimeUtil.currentTimeMillis()); } }); } }
固然,以上的代碼應該在系統初始化的時候運行,以避免在執行限流時找不到對應的規則。至因而如何實現規則的熱更新的,只須要從FlowRuleManager.register2Property方法入手跟蹤源碼便知,相對簡單。ui
除了使用文件外,Sentinel還提供了其它的一些拓展供你們直接使用,看以下的這些依賴包便能知道是作什麼的了,期原理和上面是一致的,在這就不綴訴了。this
<!-- 從nacos中拉取規則的配置 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> <version>1.8.0</version> </dependency> <!-- 從apollo中拉取規則的配置 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-apollo</artifactId> <version>1.8.0</version> </dependency> <!-- 從zookeeper中拉取規則的配置 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-zookeeper</artifactId> <version>1.8.0</version> </dependency> <!-- 從consul中拉取規則的配置 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-consul</artifactId> <version>1.8.0</version> </dependency> <!-- 從redis中拉取規則的配置 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-redis</artifactId> <version>1.8.0</version> </dependency>