sentinel是今年阿里开源的高可用防护的流量管理框架

git地址:https://github.com/alibaba/Sentinel

wiki:https://github.com/alibaba/Sentinel/wiki

FAQ:https://github.com/alibaba/Sentinel/wiki/FAQ

--------------------------------------------------------------------------------------------------------------------------------------------------------

本文对其中的DataSource扩展进行学习,此为第一部分ReadableDataSource。

sentinel-datasource-extension模块,在sentinel-extension模块下,见下图:

sentinel-datasource-extension模块主要定义了datasource扩展相关的接口,见下图:

其中,FileRefreshableDataSource、FileWritableDataSource是基于文件的DataSource的实现;

此外官方还提供了zookeeper、nacos、apolo的3个DataSource实现,参见上图的sentinel-datasource-zookeeper、sentinel-datasource-nacos、sentinel-datasource-apollo的3个模块;

首先,我们来看下sentinel-datasource-extension模块吧,先看下接口和类图结构;

在IDEA里,选中com.alibaba.csp.sentinel.datasource包下所有类和接口,右键->Diagrams->Show Diagram(Ctrl+Alt+Shift+U):

可以看到顶层有3个接口,两个DataSource,一个Converter;

顾名思义,ReadableDataSource表示读的数据源,WriteableDataSource表示写的数据源,Converter表示转换器接口;

一个个看:)

ReadableDataSource<S, T>:这是个泛型接口,其实注释很清楚了,S、T分别代码来源和结果,一般是把某个数据来源对象转换成Sentinel的Rule类,比如String->List<FlowRule>;

接口定义了4个方法:

1.T loadConfig() 从数据源中读取数据,返回T类型数据;

后面会看到,其实该方法实现通常是2步

S readSource(); // 调下面的readSource接口读取

T convert(S source); // 通过Converter<S, T>接口转换

2.S readSource() 从数据源中读取数据,返回S类型数据;

读取数据跟具体的数据源有关,需要数据源相关的api包或client;

比如从文件中读数据,通过java.io、java.nio包;

从zookeeper读取,通过org.apache.curator client api;

读数据又分为拉模式、推模式,参考sentinel官方的wiki,动态规则扩展:https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95

拉模式:继承AutoRefreshDataSource抽象类,在readSource()中实现从数据源读取数据;

推模式:继承AbstractDataSource抽象类,在构造函数中添加数据源变动的监听器,在readSource()中实现从数据源读取数据;

注:继承这两个抽象类是推荐的一种简单方式,但不是强制;

3.SentinelProperty<T> getProperty() 返回SentielProperty,注意是<T>类型

SentinelProperty<T>是一个泛型接口,在sentinel-core模块的property包下

4.void close() 关闭数据源,一般是指释放资源,比如文件类型数据源关闭文件

既然关键接口其中一个方法返回SentinelProperty<T>,那我们先去sentinel-core看看该接口和相关的实现类。

先查看接口和类图结构。同样方法,选中property包下所有类和接口,右键->Diagrams->Show Diagram(Ctrl+Alt+Shift+U):

顶层有2个接口,看名称PropertyListener可能跟SentinelProperty的监听有关。

先看SentinelProperty接口

有3个方法,看名称感觉有点像观察者模式中的监听器。

接着,我们看下它的2个实现类

NoOpSentinelProperty类方法实现为空,从名称也看得出,它不作任何操作;

对着NoOpSentinelProperty类名按住Crtl+鼠标左键,

发现只有EmptyDataSource类用到了NoOpSentinelProperty,看注释和方法,了解到这是一个空的DataSource实现,用于设置默认配置。

接着,我们重点关注SentinelProperty<T>接口的另一个实现DynamicSentinelProperty<T>

可以看到,DynamicSentinelProperty<T>定义了2个属性,

Set<PropertyListener<T>> listeners用于保存属性监听器,注意PropertyListener<T>是接口类型;

T value 用于存值;

观察addListener、removeListener方法,分别是往Set<PropertyListener<T>> listeners添加和删除监听器;

只是addListener方法添加了监听器后,调用了添加的那个监听器的listener.configLoad(value)回调方法,用于监听器处理第一次加载

在实现的void updateValue(T newValue)方法中,首先通过isEqual(value, newValue)方法,判断了新值和旧值是否相同,

如果相同,不作处理直接返回;

如果不同,首先用RecordLog.info方法记1条日志信息;

将新值赋给value,遍历监听器集合,调用回调方法listener.configUpdate(newValue);// 看到这里就很清楚了,这是典型的观察者模式

此外,DynamicSentinelProperty还提供一个public方法close用户清空监听器集合;

我们接着看PropertyListener<T>接口:

该接口提供了两个回调方法,1个是value更新回调,1个是第一次加载value回调

在看实现了PropertyListener<T>的SimplePropertyListener类:

该类是一个抽象类,重写了configLoad方法,调用configUpdate(value)方法,意思就是第一次加载回调复用更新回调的逻辑。

到这里,我们并没有看到PropertyListener<T>接口的具体实现类,

选中PropertyListener文件,Ctrl+H查看类继承结构:

可以看到除SimplePropertyListener抽象类外,有6个类直接或间接实现了PropertyListener<T>,通过静态内部类或匿名内部类;

限于篇幅,本文就不展开了。

对sentinel-core下的property包简单总结下:定义了属性和监听器接口,其中DynamicSentinelProperty通过观察者模式,实现了属性的第一次加载和变动的回调通知

我们回到datasource包,顺着ReadableDataSource的继承结构看:

先看AbstractDataSource<S,T>:

实现了ReadableDataSource<S,T>的两个接口,T loadConfig()和 SentinelProperty<T> getProperty()

定义了两个属性,一个转换器Converter<S, T> parser,一个前文提到的SentinelProperty<T> property;

可以看到getProperty()直接返回propery即可;

而loadConfig()方法,首先调用接口中的readSource()方法得到S数据,再调用parser.convert转换成T数据// ps:这里变量名是parser,因Converter接口重构过,以前版本叫ConfigParser接口,后来抽象出了WritableDataSource接口,

S->T、T->S都有转换,因此ConfigParser改为Converter

构造函数中,需要传入一个Converter<S,T>对象,并且验证不能为null;而SentinelProperty<T> property使用了之前提到的DynamicSentinelProperty<T>实现;

再来看AutoRefreshDataSource<S, T>抽象类:

该类扩展了AbstractDataSource<S, T>,在基础上通过ScheduledExecutorService使用后台线程,定时刷新数据(即轮询方式的拉模式),

抽象了一个protected boolean isModified()方法,用于子类实现,判断数据源是否发生了数据变化;

T newValue = loadConfig(); // 还记得AbstractDataSource<S, T>实现了loadConfig吗,通过readSource()、parser.convert()两步实现
getProperty().updateValue(newValue);// 这两句很关键,自定义实现也会用到,读取数据,更新SentinelProperty。

实现了close()方法,用ScheduledExecutorService的shutdownNow()方法,进行了线程的关闭;

注意:AutoRefreshDataSource<S, T>仍然是个抽象类,因为它没有实现具体S readSource()方法,留给具体数据源的子类实现;

接下来,我们下一个类FileRefreshableDataSource,终于该类不是抽象类了:)  可以new使用。

该类代码较多,就不贴完了,首先继承AutoRefreshDataSource<String, T>,注意:泛型S已经没有了,而是具体的String,说明T readSource方法返回的是String,Converter<S, T>中的转换来源也是String;

静态属性文件读取的固定参数,比如文件缓冲区最大限制,字符类型等;

类属性定义了缓存区字节数组、文件等;

来看关键的两个方法:

readSource是抽象类中没有实现的方法了,这里有了具体实现,从文件中读取数据,并返回String;

isModifed方法根据文件修改时间判断是否数据源(即文件内容)发生了变化;

我们看看FileRefreshableDataSource具体哪里用到的;按住Ctrl键,对着类名点左键:

找到了它的demo示例,在sentinel-demo模块的子模块sentinel-demo-dynamic-file-rule下:

可以看到,使用FileFreashDataSource就4步:

1.定义文件路径

2.定义String到List<XxxRule>转换器

3.构造FileFreashDataSource

4.用XxxRuleManager.register2Property加载

--------------------------------------------------------------------------------------------------------------------------------------------------------

最后,我们对ReadableDataSource做个简单的总结:

层次结构:ReadableDataSource->AbstractDataSource->AutoRefreshDataSource->FileRefreshDataSource

T loadConfig() 读取数据源并转换为T类型,调用readSource()得到S,调用Converter<S,T> 得到T

S readSource()  读取数据源,得到S

SentinelProperty<T> getProperty()  获取SentinelProperty<T>接口,一般是DynamicSentinelProperty<T>类型

一次从读取数据源到更新数据过程:通过loadConfig()得到T,getProperty().updateValue(T)

拉模式:继承AutoRefreshDataSource抽象类,在readSource()中实现从数据源读取数据;

例:FileRefreshDataSource

推模式:继承AbstractDataSource抽象类,在构造函数中添加数据源变动的监听器,在readSource()中实现从数据源读取数据;

例:ZookeeperDataSource、NacosDataSource、ApolloDataSource

// 再回过头去看最开始的类图,可以发现sentinel的datasource这样的泛型接口和抽象类结构定义是比较优雅的,让自定义DataSource实现变得更加简单:)

--------------------------------------------------------------------------------------------------------------------------------------------------------

思考:

SentinelProperty<T>接口没有提供getValue方法,不能获取T value;

只能通过给SentinelProperty添加监听器PropertyListener<T>,并在回调方法void configUpdate(T value)、void configLoad(T value)时,能够访问value;

// 个人理解可能这是一种对property中value的保护

--------------------------------------------------------------------------------------------------------------------------------------------------------

参考:

sentinel官方wiki-动态规则扩展 https://github.com/alibaba/Sentinel/wiki/动态规则扩展

聊聊sentinel的DataSource https://my.oschina.net/go4it/blog/1929547

[学习]sentinel中的DatatSource(一) ReadableDataSource的更多相关文章

  1. [学习]sentinel中的DatatSource(二) WritableDataSource

    sentinel是今年阿里开源的高可用防护的流量管理框架. git地址:https://github.com/alibaba/Sentinel wiki:https://github.com/alib ...

  2. Redis Sentinel中的机制与原理详解

    序言 Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案.实际上这意味着你可以使用Sentinel模式创建一个可以不用人为干预而应对各种故障的Redis部署. 它的主要功能有以 ...

  3. 学习sql中的排列组合,在园子里搜着看于是。。。

    学习sql中的排列组合,在园子里搜着看,看到篇文章,于是自己(新手)用了最最原始的sql去写出来: --需求----B, C, F, M and S住在一座房子的不同楼层.--B 不住顶层.C 不住底 ...

  4. [转]学习Nop中Routes的使用

    本文转自:http://www.cnblogs.com/miku/archive/2012/09/27/2706276.html 1. 映射路由 大型MVC项目为了扩展性,可维护性不能像一般项目在Gl ...

  5. Redis学习-Sentinel

    Redis的Sentinel系统用于管理多个Redis服务器(instance), 该系统执行以下三个任务: 监控(Monitoring):Sentinel会不断地检查你的主服务器和从服务器是否运作正 ...

  6. Android学习开发中如何保持API的兼容

    Android学习开发中如何保持API的兼容: 1,采用良好的设计思路 在设计过程中,如果能按照下面的方式来进行设计,会让这个API生命更长久 面向用例的设计,收集用户建议,把自己模拟成用户,保证AP ...

  7. redis 系列24 哨兵Sentinel (中)

    四. 检测下线状态 对于Redis的Sentinel中关于下线有两个不同的概念:(1)主观下线(Subjectively Down, 简称 Sdown) 指的是单个 Sentinel 实例对服务器做出 ...

  8. 学习Spring中遇到关于BeanFactory及测试类的问题

    最近在学习Spring,使用的是Spring 5.0.1 学习书本中使用的是4.0 学习书本中使用以下来加载配置文件及设置 Resource resource = new ClassPathResou ...

  9. 斯坦福大学公开课机器学习:machine learning system design | trading off precision and recall(F score公式的提出:学习算法中如何平衡(取舍)查准率和召回率的数值)

    一般来说,召回率和查准率的关系如下:1.如果需要很高的置信度的话,查准率会很高,相应的召回率很低:2.如果需要避免假阴性的话,召回率会很高,查准率会很低.下图右边显示的是召回率和查准率在一个学习算法中 ...

随机推荐

  1. ES6入门九:Symbol元编程

    JS第七种数据类型:Symbol Symbol的应用场景 11个Symbol静态属性 Symbol元编程 一.JS第七种数据类型:Symbol 在ES6之前的JavaScript的基本数据类型有und ...

  2. ES6入门六:class的基本语法、继承、私有与静态属性、修饰器

    基本语法 继承 私有属性与方法.静态属性与方法 修饰器(Decorator) 一.基本语法 class Grammar{ constructor(name,age){ //定义对象自身的方法和属性 t ...

  3. JavaScript获取数组索引

    JavaScript获取数组索引: <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...

  4. vue项目中图片预览旋转功能

    最近项目中需要在图片预览时,可以旋转图片预览,在网上找了下,发现有一款功能强大的图片组件:viewerjs. git-hup: https://github.com/fengyuanchen/view ...

  5. 【loj#6220】sum

    题目传送门:https://loj.ac/problem/6220 题意:对于一个序列$a$,找出它的一个子序列$b$,使$\sum_{a_i \in b}a_i \equiv 0 \pmod n$ ...

  6. 团队第三次作业:Alpha版本发布

    这个作业属于哪个课程 课程链接 这个作业要求在哪里 作业要求链接 团队名称 众志陈成 这个作业的目标 通过团队协作了解软件开发的大致流程,并在这个过程中体会调整与优化程序的方法,为以后真实的软件开发奠 ...

  7. SqlMetaData异常 dbType xx 对于此构造函数无效。

    今天在dapper中想扩展使用表值类型参数——tableValue.但是dapper不支持此类参数,于是扩展了一下.其中出现了一个问题. Microsoft.SqlServer.Server.SqlM ...

  8. TODO redis学习笔记

    redis官网教程地址:http://try.redis.io/ redis脚本和命令部分来自:https://www.runoob.com/redis/redis-security.html red ...

  9. H5 页面 rem 布局适配方法

    rem 布局适配方案 主要方法为: 按照设计稿与设备宽度的比例,动态计算并设置 html 根标签的 font-size 大小: css 中,设计稿元素的宽.高.相对位置等取值,按照同等比例换算为 re ...

  10. [MySQL优化] -- 如何了解SQL的执行频率

    MySQL 客户端连接成功后,通过 show [session|global]status 命令 可以提供服务器状态信息,也可以在操作系统上使用 mysqladmin extended-status ...