风止雨歇

Sentinel的持久化

官网地址:https://github.com/alibaba/Sentinel/wiki/%E5%9C%A8%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Sentinel

一、规则管理及推送

Sentinel-dashboard配置的规则是基于内存的,在微服务以及控制台重启的时候就清空了;

一般来说,规则的推送有下面三种模式:

 1、原始模式

如果不做任何修改,Dashboard 的推送规则方式是通过 API 将规则推送至客户端并直接更新到内存中;

优缺点:这种做法的好处是简单,无依赖;坏处是应用重启规则就会消失,仅用于简单测试,不能用于生产环境

2、Pull模式

  pull 模式的数据源(如本地文件、RDBMS 等)一般是可写入的。使用时需要在客户端注册数据源:将对应的读数据源注册至对应的 RuleManager,将写数据源注册至 transport 的 WritableDataSourceRegistry 中。

 

   首先 Sentinel 控制台通过 API 将规则推送至客户端并更新到内存中,接着注册的写数据源会将新的规则保存到本地的文件中。使用 pull 模式的数据源时一般不需要对 Sentinel 控制台进行改造。

  这种实现方法好处是简单,不引入新的依赖,坏处是无法保证监控数据的一致性。

(1)通过SPI扩展机制进行扩展,在resources目录下创建 META-INF/services/com.alibaba.csp.sentinel.init.InitFunc 文件;我们写一个拉模式的实现类  com.yufeng.persistence.PullModeByFileDataSource ,并将这个类的全类名写入到文件中。

 (2)实现的类  PullModeByFileDataSource 类,如下:

  1 @Slf4j
  2 public class PullModeByFileDataSource implements InitFunc {
  3 
  4     @Override
  5     public void init() {
  6         log.info("time:{}读取配置", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")));
  7 
  8         // 1. 创建文件夹
  9         try {
 10             this.mkdirIfNotExits(PersistenceRuleConstant.storePath);
 11     
 12             // 2. 创建文件
 13             this.createFileIfNotExits(PersistenceRuleConstant.rulesMap);
 14     
 15             // 3.处理流控规则
 16             this.dealFlowRules();
 17     
 18             // 4.处理降级规则
 19             this.dealDegradeRules();
 20     
 21             // 5.处理系统规则
 22             this.dealSystemRules();
 23     
 24             // 6.处理热点参数规则
 25             this.dealParamFlowRules();
 26     
 27             // 7.处理授权规则
 28             this.dealAuthRules();
 29         } catch (IOException e) {
 30             log.error("错误原因:{}",e);
 31         }
 32     }
 33 
 34     /**
 35      * 处理流控规则
 36      */
 37     private void dealFlowRules() throws FileNotFoundException {
 38         String ruleFilePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.FLOW_RULE_PATH).toString();
 39 
 40         // 1. 创建流控规则的可读数据源
 41         ReadableDataSource<String, List<FlowRule>> flowRuleRds = new FileRefreshableDataSource<> (
 42                 ruleFilePath, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {})
 43         );
 44 
 45         // 2. 将可读数据源注册至FlowRuleManager 这样当规则文件发生变化时,就会更新规则到内存
 46         FlowRuleManager.register2Property(flowRuleRds.getProperty());
 47 
 48         WritableDataSource<List<FlowRule>> flowRuleWds = new FileWritableDataSource<List<FlowRule>>(
 49                 ruleFilePath, JSON::toJSONString);
 50 
 51         // 3. 将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.
 52         // 这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.
 53         WritableDataSourceRegistry.registerFlowDataSource(flowRuleWds);
 54     }
 55 
 56     /**
 57      * 降级规则
 58      */
 59     private void dealDegradeRules() throws FileNotFoundException {
 60         String degradeRuleFilePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.DEGRAGE_RULE_PATH).toString();
 61 
 62         // 1. 创建流控规则的可读数据源
 63         ReadableDataSource<String, List<DegradeRule>> degradeRuleRds = new FileRefreshableDataSource<>(
 64                 degradeRuleFilePath, source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {})
 65         );
 66 
 67         // 2.将可读数据源注册至FlowRuleManager 这样当规则文件发生变化时,就会更新规则到内存
 68         DegradeRuleManager.register2Property(degradeRuleRds.getProperty());
 69 
 70         WritableDataSource<List<DegradeRule>> degradeRuleWds = new FileWritableDataSource<>(
 71                 degradeRuleFilePath, JSON::toJSONString
 72         );
 73 
 74         // 3. 将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.
 75         // 这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.
 76         WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWds);
 77     }
 78 
 79     /**
 80      * 处理系统规则
 81      */
 82     private void dealSystemRules() throws FileNotFoundException {
 83         String systemRuleFilePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.SYSTEM_RULE_PATH).toString();
 84 
 85         // 1.创建流控规则的可读数据源
 86         ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(
 87                 systemRuleFilePath, source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>() {})
 88         );
 89 
 90         // 2.将可读数据源注册至FlowRuleManager 这样当规则文件发生变化时,就会更新规则到内存
 91         SystemRuleManager.register2Property(systemRuleRDS.getProperty());
 92 
 93         WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(
 94                 systemRuleFilePath, JSON::toJSONString
 95         );
 96 
 97         // 3.将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.
 98         // 这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.
 99         WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
100     }
101 
102     /**
103      * 热点参数规则
104      */
105     private void dealParamFlowRules() throws FileNotFoundException {
106         String paramFlowRuleFilePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.HOT_PARAM_RULE).toString();
107 
108         // 1. 创建流控规则的可读数据源
109         ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(
110                 paramFlowRuleFilePath, source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {})
111         );
112 
113         // 2. 将可读数据源注册至FlowRuleManager 这样当规则文件发生变化时,就会更新规则到内存
114         ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
115 
116         WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(
117                 paramFlowRuleFilePath, JSON::toJSONString
118         );
119 
120         // 3. 将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.
121         // 这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.
122         ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
123     }
124 
125     /**
126      * 方法实现说明:授权规则
127      * @author:smlz
128      * @return:
129      * @exception:
130      * @date:2019/11/29 13:56
131      */
132     private void dealAuthRules() throws FileNotFoundException {
133         String authFilePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.AUTH_RULE_PATH).toString();
134 
135         // 1.创建流控规则的可读数据源
136         ReadableDataSource<String, List<AuthorityRule>> authRuleRDS = new FileRefreshableDataSource<>(
137                 authFilePath, source -> JSON.parseObject(source, new TypeReference<List<AuthorityRule>>() {})
138         );
139 
140         // 2.将可读数据源注册至FlowRuleManager 这样当规则文件发生变化时,就会更新规则到内存
141         AuthorityRuleManager.register2Property(authRuleRDS.getProperty());
142 
143         WritableDataSource<List<AuthorityRule>> authRuleWDS = new FileWritableDataSource<>(
144                 authFilePath, JSON::toJSONString
145         );
146 
147         // 3.将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.
148         // 这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.
149         WritableDataSourceRegistry.registerAuthorityDataSource(authRuleWDS);
150     }
151 
152     /**
153      * 创建文件目录
154      */
155     private void mkdirIfNotExits(String filePath) throws IOException {
156         File file = new File(filePath);
157         if(!file.exists()) {
158             log.info("创建Sentinel规则目录:{}",filePath);
159             file.mkdirs();
160         }
161     }
162 
163     /**
164      * 创建规则文件
165      */
166     private void createFileIfNotExits(Map<String,String> ruleFileMap) throws IOException {
167         for (Map.Entry entry : ruleFileMap.entrySet()) {
168             String ruleFilePath  = PersistenceRuleConstant.rulesMap.get(entry.getKey()).toString();
169             File ruleFile = new File(ruleFilePath);
170             if(!ruleFile.exists()) {
171                 log.info("创建Sentinel 规则文件:{}",ruleFile);
172                 ruleFile.createNewFile();
173             }
174         }
175     }
176 }

(3)常量类的定义

 1 public class PersistenceRuleConstant {
 2 
 3     /**
 4      * 存储文件路径
 5      */
 6     public static final String storePath = System.getProperty("user.home")+"\\sentinel\\rules\\";
 7 
 8     /**
 9      * 各种存储sentinel规则映射map
10      */
11     public static final Map rulesMap = new HashMap<String,String>();
12 
13     //流控规则文件
14     public static final String FLOW_RULE_PATH = "flowRulePath";
15 
16     //降级规则文件
17     public static final String DEGRAGE_RULE_PATH = "degradeRulePath";
18 
19     //授权规则文件
20     public static final String AUTH_RULE_PATH = "authRulePath";
21 
22     //系统规则文件
23     public static final String SYSTEM_RULE_PATH = "systemRulePath";
24 
25     //热点参数文件
26     public static final String HOT_PARAM_RULE = "hotParamRulePath";
27 
28     static {
29         rulesMap.put(FLOW_RULE_PATH,storePath + "flowRule.json");
30         rulesMap.put(DEGRAGE_RULE_PATH,storePath + "degradeRule.json");
31         rulesMap.put(SYSTEM_RULE_PATH,storePath + "systemRule.json");
32         rulesMap.put(AUTH_RULE_PATH,storePath + "authRule.json");
33         rulesMap.put(HOT_PARAM_RULE,storePath + "hotParamRule.json");
34     }
35 }

 3、Push模式

  生产环境下一般更常用的是 push 模式的数据源。对于 push 模式的数据源,如远程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不应由 Sentinel 客户端进行,而应该经控制台统一进行管理,直接进行推送,数据源仅负责获取配置中心推送的配置并更新到本地。因此推送规则正确做法应该是 配置中心控制台/Sentinel 控制台 → 配置中心 → Sentinel 数据源 → Sentinel,而不是经 Sentinel 数据源推送至配置中心。这样的流程就非常清晰了:

 

 原理简述

(1)控制台推送规则:

  •  将规则推送到Nacos或其他远程配置中心;
  • Sentinel客户端链接Nacos,获取规则配置;并监听Nacos配置变化,如发生变化,就更新本地缓存(从而让本地缓存总是和Nacos一致);

(2)控制台监听Nacos配置变化,如发生变化就更新本地缓存(从而让控制台本地缓存总是和Nacos一致)

改造方案

 

posted on 2021-08-19 20:56  风止雨歇  阅读(571)  评论(0编辑  收藏  举报

导航