Sentinel規則配置以外部數據源

在前面的示例中,對於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

Sentinel規則配置以外部數據源

其中的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>

Sentinel規則配置以外部數據源

相關文章
相關標籤/搜索