文章目录
- 一、拉模式架构
- 二、原理简述
- 三、编写
- 3.1 加依赖
- 3.2 写代码
- 3.3 配置
- 四、优缺点分析
- 五、你可能会有的疑问
- 六、参考文档
- 七、案例测试
- 7.1. 添加流控规则
- 7.2. 服务停止
- 7.3. 重新启动服务
- 7.4. 调用接口
- 7.5. 查看流控规则
本文实现基于拉模式的Alibaba Sentinel规则持久化。
一、拉模式架构
图片来自官方。
引用自 https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel
二、原理简述
FileRefreshableDataSource 定时从指定文件中读取规则JSON文件【图中的本地文件】,如果发现文件发生变化,就更新规则缓存。
FileWritableDataSource 接收控制台规则推送,并根据配置,修改规则JSON文件【图中的本地文件】。
三、编写
修改Spring Cloud Alibaba微服务。
3.1 加依赖
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-extension</artifactId>
</dependency>
3.2 写代码
package com.itmuch.contentcenter.sentinel;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;/*** 拉模式规则持久化** @author itmuch.com*/
public class FileDataSourceInit implements InitFunc {@Overridepublic 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 paramFlowRulePath = ruleDir + "/param-flow-rule.json";this.mkdirIfNotExits(ruleDir);this.createFileIfNotExits(flowRulePath);this.createFileIfNotExits(degradeRulePath);this.createFileIfNotExits(systemRulePath);this.createFileIfNotExits(authorityRulePath);this.createFileIfNotExits(paramFlowRulePath);// 流控规则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<>(authorityRulePath,authorityRuleListParser);AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(authorityRulePath,this::encodeJson);WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);// 热点参数规则ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(paramFlowRulePath,paramFlowRuleListParser);ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(paramFlowRulePath,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>> paramFlowRuleListParser = source -> JSON.parseObject(source,new TypeReference<List<ParamFlowRule>>() {});private void mkdirIfNotExits(String filePath) throws IOException {File file = new File(filePath);if (!file.exists()) {file.mkdirs();}}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);}
}
3.3 配置
在项目的 resources/META-INF/services
目录下创建文件,名为 com.alibaba.csp.sentinel.init.InitFunc
,内容为:
# 改成上面FileDataSourceInit的包名类名全路径即可。
com.itmuch.contentcenter.sentinel.FileDataSourceInit
四、优缺点分析
优点:
简单易懂
没有多余依赖(比如配置中心、缓存等)
缺点:
由于规则是用 FileRefreshableDataSource 定时更新的,所以规则更新会有延迟。如果FileRefreshableDataSource定时时间过大,可能长时间延迟;如果FileRefreshableDataSource过小,又会影响性能;
规则存储在本地文件,如果有一天需要迁移微服务,那么需要把规则文件一起迁移,否则规则会丢失。
五、你可能会有的疑问
Spring Cloud Alibaba不是提供了如下配置了吗?为什么要全部自己写呢?
spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow#spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
#spring.cloud.sentinel.datasource.ds1.file.data-type=custom
#spring.cloud.sentinel.datasource.ds1.file.converter-class=com.alibaba.cloud.examples.JsonFlowRuleListConverter
#spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
关于这个问题,可以参考提的Issuehttps://github.com/alibaba/spring-cloud-alibaba/issues/756):
六、参考文档
https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel#pull模式
七、案例测试
7.1. 添加流控规则
簇点链路-流控
7.2. 服务停止
停止内容中心和Sentinel控制台
7.3. 重新启动服务
重新启动Sentinel控制台和内容中心
7.4. 调用接口
由于Sentinel控制台采用的是懒加载策略,因此,需要请求一次接口,再刷新
http://localhost:8010/shares/1
7.5. 查看流控规则
刷新Sentinel控制台,查看流控规则