1、背景
当前项目没有接入配置中心、只针对两三个对外三方接口做熔断降级,最初的预想是尽量简单化实现,所以在考虑的时候想着尽量把服务端dashboard剥离出来,监控指标可以后续再调研是否可以暴露给grafana,抱着这个目的开始了一番调研。
2、实施
sentinel规则一共有三种模式
推送模式 | 说明 | 优点 | 缺点 |
---|---|---|---|
原始模式 | API 将规则推送至客户端并直接更新到内存中,扩展写数据源(WritableDataSource) | 简单,无任何依赖 | 不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境 |
Pull模式 | 扩展写数据源(WritableDataSource), 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件 等 | 简单,无任何依赖;规则持久化 | 不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。 |
Push模式 | 扩展读数据源(ReadableDataSource),规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源。 | 规则持久化;一致性;快速 | 引入第三方依赖 |
2.1、原始模式
2.1.1、原始模式下使用dashboard
这个模式是dashboard修改的规则的默认模式,在使用dashboard修改规则后,会调用客户端的api接口同步规则,客户端会讲规则存入内存,也就是说如果重启服务,规则就会荡然无存。所以,这种模式只适合在测试或者写demo的时候使用。
2.1.2、原始模式下不使用dashboard
离开dashboard,可以手动写死或者实现WritableDataSource(具体介绍参考2.2),不过个人认为原始模式就是追求简单,与其实现WritableDataSource再配置,不如直接写死来的简单。 代码如下,不过会带来另一个问题:无法动态修改,所以依旧是一个缺陷很多的模式。
private void initRules() {
//=============================规则1=========================
FlowRule rule1 = new FlowRule();
rule1.setResource("rule1");//规则名称
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);//如果设置0则按照线程数限流,如果设置1则按照QPS(每秒查询率)限流
rule1.setCount(100); // 每秒调用最大次数为 100 次
rule1.setControlBehavior(0);//0快速失败,1预警,2排队等候
rule1.setMaxQueueingTimeMs(1000);//排队超时阈值
//=============================规则2=========================
FlowRule rule2 = new FlowRule();
rule2.setResource("rule2");
rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule2.setCount(10); // 每秒调用最大次数为 10 次
List<FlowRule> rules = new ArrayList<>();
rules.add(rule1);
rules.add(rule2);
FlowRuleManager.loadRules(rules);
}
2.2 Pull模式
这种模式相较于原始模式有了很大的改变,服务在启动的时候会将对应的读数据源注册至对应的 RuleManager,将写数据源注册至 transport 的 WritableDataSourceRegistry 中,即加载到内存里。同时在写入后,服务端也会定时去轮询查询最新的规则并同步到内存。如果使用dashboard修改规则后,dashboard会调用客户端api来推送规则,接着客户端会将规则写入内存,并持久化。
以本地文件数据源为例
public class FileDataSourceInit implements InitFunc {
@Override
public void init() throws Exception {
String flowRulePath = "xxx";
ReadableDataSource<String, List<FlowRule>> ds = new FileRefreshableDataSource<>(
flowRulePath, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {})
);
// 将可读数据源注册至 FlowRuleManager.
FlowRuleManager.register2Property(ds.getProperty());
WritableDataSource<List<FlowRule>> wds = new FileWritableDataSource<>(flowRulePath, this::encodeJson);
// 将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.
// 这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.
WritableDataSourceRegistry.registerFlowDataSource(wds);
}
private <T> String encodeJson(T t) {