阅读文本大约需要3分钟。我在网上看到一篇关于这个的文章:
从官网说明
https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel#Pull模式
有以下图片,总觉得例子缺少什么??
经过深思熟虑,我发现无论是官方的例子还是网民的例子,都没有结合Sentinel来解释规则。现在开始操作,按照官方步骤开始操作:
https://github.com/alibaba/Sentinel/wiki/扩展动态规则
pom在微服务中.介绍xml文件
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-extension</artifactId> <version>x.y.z</version></dependency>
不知道哪里出了问题,最后也没搞清楚。还有以下问题
- 微服务连接哪个Sentinel服务?如果没有配置,可以连接默认的Sentinel服务
- 如果Sentinel服务的ip和port发生了变化?如何配置?还没有找到具体的解释?
带着这两个问题开始学习之旅。因为基于springboot和springcloud的解释,所有的spring Cloud 为什么不用Alibaba这么好的技术呢?
0x01:olive新建项目-pull-sentinel-datasource
- pom.介绍xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.sentinel</groupId> <artifactId>olive-pull-sentinel-datasource</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <name>olive-pull-sentinel-datasource</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.2.1.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-parameter-flow-control</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version> 1.2.68</version> </dependency> </dependencies></project>
- 编写以下代码
常量类主要定义规则文件的目录和名称
package com.sentinel.olive.file;import java.util.HashMap;import java.util.Map;public class PersistenceRuleConstant { /** * 存储文件路径 */ public static final String storePath = System.getProperty("user.home"""sentinel\\rules\\"; /** * 各种存储sentinel规则映射map */ public static final Map<String,String> rulesMap = new HashMap<String,String>(); ///流控规则文件 public static final String FLOW_RULE_PATH = "flowRulePath"; //降级规则文件 public static final String DEGRAGE_RULE_PATH = "degradeRulePath"; //授权规则文件 public static final String AUTH_RULE_PATH = "authRulePath"; ///系统规则文件 public static final String SYSTEM_RULE_PATH = "systemRulePath"; //热点参数文件 public static final String HOT_PARAM_RULE = "hotParamRulePath"; static { rulesMap.put(FLOW_RULE_PATH,storePath+"flowRule.json"); rulesMap.put(DEGRAGE_RULE_PATH,storePath+"degradeRule.json"); rulesMap.put(SYSTEM_RULE_PATH,storePath+"systemRule.json"); rulesMap.put(AUTH_RULE_PATH,storePath+"authRule.json"); rulesMap.put(HOT_PARAM_RULE,storePath+"hotParamRule.json"); }}
文件操作类,如果没有规则文件,创建相应的目录和相应的规则文件
package com.sentinel.olive.file;import java.io.File;import java.io.IOException;import java.util.Iterator;import java.util.Map;import java.util.Set;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class RuleFileUtils { private static final Logger logger = LoggerFactory.getLogger(RuleFileUtils.class); /** * 方法实现说明:如果路径不存在,则创建路径 * @param filePath:存储文件的路径 */ public static void mkdirIfNotExits(String filePath) throws IOException { File file = new File(filePath); if(!file.exists()) { logger.info(创建Sentinel规则目录:{}filePath); file.mkdirs(); } } /** * 方法实现说明:如果文件不存在,则创建路径 * @param ruleFileMap 存储文件的规则 */ public static void createFileIfNotExits(Map<String,String> ruleFileMap) throws IOException { Set<String> ruleFilePathSet = ruleFileMap.keySet(); Iterator<String> ruleFilePathIter = ruleFilePathSet.iterator(); while (ruleFilePathIter.hasNext()) { String ruleFilePathKey = ruleFilePathIter.next(); String ruleFilePath = PersistenceRuleConstant.rulesMap.get(ruleFilePathKey).toString(); File ruleFile = new File(ruleFilePath); if(ruleFile.exists()) { logger.info(”创建Sentinelel 规则文件:{}ruleFile); ruleFile.createNewFile(); } } }}
编码和解码操作规则
package com.sentinel.olive.file;import java.util.List;import com.alibaba.csp.sentinel.datasource.Converter;import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;import com.alibaba.csp.sentinel.slots.system.SystemRule;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.TypeReference;public class RuleListParserUtils { /** * 流控列表分析器 */ public static final Converter<String, List<FlowRule>> flowRuleListParser = new Converter<String, List<FlowRule>>() { @Override public List<FlowRule> convert(String source) { return JSON.parseObject(source, new TypeReference<List<FlowRule>>() { }); } }; /** * 流控列表 编码器 */ public static final Converter<List<FlowRule>, String> flowRuleEnCoding = new Converter<List<FlowRule>, String>() { @Override public String convert(List<FlowRule> source) { return JSON.toJSONString(source); } }; public static final Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() { }); public static final Converter<List<DegradeRule>, String> degradeRuleEnCoding = new Converter<List<DegradeRule>, String>() { @Override public String convert(List<DegradeRule> source) { return JSON.toJSONString(source); } }; public static final Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>() { }); public static final Converter<List<SystemRule>, String> systemRuleEnCoding = new Converter<List<SystemRule>, String>() { @Override public String convert(List<SystemRule> source) { return JSON.toJSONString(source); } }; public static final Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON .parseObject(source, new TypeReference<List<AuthorityRule>>() { }); public static final Converter<List<AuthorityRule>, String> authorityRuleEnCoding = new Converter<List<AuthorityRule>, String>() { @Override public String convert(List<AuthorityRule> source) { return JSON.toJSONString(source); } }; public static final Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON .parseObject(source, new TypeReference<List<ParamFlowRule>>() { });// public static final Converter<List<ParamFlowRule>, String> paramFlowRuleEnCoding = new Converter<List<ParamFlowRule>, String>() {// @Override// public String convert(List<ParamFlowRule> source) {// return JSON.toJSONString(source);// }// }; public static final Converter<List<ParamFlowRule>, String> paramFlowRuleEnCoding = source -> encodeJson(source); private static <T> String encodeJson(T t) { return JSON.toJSONString(t); }}
具体pull模式操作类型
package com.sentinel.olive.file;import java.io.FileNotFoundException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.List;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;import com.alibaba.csp.sentinel.datasource.FileWritableDataSource;import com.alibaba.csp.sentinel.datasource.ReadableDataSource;import com.alibaba.csp.sentinel.datasource.WritableDataSource;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;public class PullModeLocalFileDataSource implements InitFunc { private static final Logger logger = LoggerFactory.getLogger(PullModeLocalFileDataSource.class); private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); @Override public void init() throws Exception { logger.info("time:{}读取配置, sdf.format(new Date())); try { // 创建文件存储目录(如果路径不存在,则创建路径) RuleFileUtils.mkdirIfNotExits(PersistenceRuleConstant.storePath); // ()创建规则文件() RuleFileUtils.createFileIfNotExits(PersistenceRuleConstant.rulesMap); // 处理流控规则逻辑 dealFlowRules(); // 处理降级规则 dealDegradeRules(); // 处理系统规则 dealSystemRules(); // 热点参数规则 dealParamFlowRules(); // 授权规则 dealAuthRules(); } catch (Exception e) { logger.error(错误原因:{} e); } } /** * 方法实现说明:处理流控规则逻辑 */ private void dealFlowRules() throws FileNotFoundException { String ruleFilePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.FLOW_RULE_PATH).toString(); // 可读数据源创建流控规则 ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(ruleFilePath, RuleListParserUtils.flowRuleListParser); // 将可读数据源注册为Flowrulemanger 这样,当规则文件发生变化时,将规则更新到内存 FlowRuleManager.register2Property(flowRuleRDS.getProperty()); WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<List<FlowRule>>(ruleFilePath, RuleListParserUtils.flowRuleEnCoding); // 注册可写数据源 transport 模块的 WritableDataSourceRegistry 中. // 当收到控制台推送规则时,Sentinel 内存将首先更新,然后在文件中写入规则. WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS); } // 处理降级规则 private void dealDegradeRules() throws FileNotFoundException { String degradeRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.DEGRAGE_RULE_PATH).toString(); // 降级规则 ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(degradeRulePath, RuleListParserUtils.degradeRuleListParser); DegradeRuleManager.register2Property(degradeRuleRDS.getProperty()); WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(degradeRulePath, RuleListParserUtils.degradeRuleEnCoding); WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS); } // 处理系统规则 private void dealSystemRules() throws FileNotFoundException { String systemRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.SYSTEM_RULE_PATH).toString(); // 系统规则 ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(systemRulePath, RuleListParserUtils.systemRuleListParser); SystemRuleManager.register2Property(systemRuleRDS.getProperty()); WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(systemRulePath, RuleListParserUtils.systemRuleEnCoding); WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS); } // 热点参数规则 private void dealParamFlowRules() throws FileNotFoundException { String paramFlowRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.HOT_PARAM_RULE).toString(); // 热点参数规则 ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>( paramFlowRulePath, RuleListParserUtils.paramFlowRuleListParser); ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty()); WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(paramFlowRulePath, RuleListParserUtils.paramFlowRuleEnCoding); ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS); } private void dealAuthRules() throws FileNotFoundException { String authFlowRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.AUTH_RULE_PATH).toString(); // 授权规则 ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(authFlowRulePath, RuleListParserUtils.authorityRuleListParser); AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty()); WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(authFlowRulePath, RuleListParserUtils.authorityRuleEnCoding); WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS); }}
可以通过SPI扩展机制编写上述代码进行扩展,在微服务工程中进行扩展 olive-pull-sentinel-在datasourceresresources目录下创建META-INF/services目录,新文件名为com.alibaba.csp.sentinel.init.InitFunc文件。内容是Pullmodelfiledatasource类全路径名称
0x02:aplication配置文件.yml
看到这张图总是解决上述问题,提供配置项,配置Sentinel服务对应的ip和端口
0x03:创建测试控制器和springboot启动类
测试控制器
package com.sentinel.olive.controller;import java.util.HashMap;import java.util.Map;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class UserController { @GetMapping("/getUser") public Map<String, Object> getUser() { Map<String, Object> result = new HashMap<>(); result.put("code", "000000"); result.put("message", "ok"); return result; }}
springboot启动类
package com.sentinel.olive;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
0x04:启动并测试验证
启动服务
- sentinel-dashboard服务
- olive-pull-sentinel-datasource微服务
验证
- sentinel-dashboard创建规则,olive-pull-sentinel-datasource微服务检测sentinel-dashboard变化
- 修改json规则文件的规则,sentinel-dashboard检测到json规则编码
httpp访问微服务://localhost:866/getuser接口
访问sentinel-dashboard服务:http://127.0.0.1:8080/
创建流控规则
olive-pull-sentinel-datasource检测到流控规则的变化,并产生flowrule.json文件
修改流控规则文件json
sentinel-dashboard查看规则的变化