[实战]扩展一个定制的sentinel JdbcDataSource
Sentinel是今年阿里开源的高可用防护的流量管理框架。
git地址:https://github.com/alibaba/Sentinel
wiki:https://github.com/alibaba/Sentinel/wiki
FAQ:https://github.com/alibaba/Sentinel/wiki/FAQ
--------------------------------------------------------------------------------------------------------------------------------------------------------
[学习]sentinel中的DatatSource(一) ReadableDataSource
[学习]sentinel中的DatatSource(二) WritableDataSource
前两篇学习了sentinel中的ReadableDataSource、WritableDataSource,接着咱们来尝试用MySQL数据库作存储,扩展一个定制的sentinel JdbcDataSource。
代码参考:https://github.com/cdfive/sentinel-support/tree/master/src/main/java/com/winxuan/sentinel/support/datasource/jdbc
--------------------------------------------------------------------------------------------------------------------------------------------------------
数据库表设计
约定:
1. 所有表名以sentinel_为前缀便于标识,字段名称如果跟MySQL关键字冲突前面加下划线
2. 应用表通过_name、ip、_port确定一个应用
3. 规则表通过app_id关联是哪一个应用
4. 查询规则时带上条件enabled=1 AND deleted=0,sentinel客户端接收有效的规则
5. resource_type、enabled、deleted、change_status等字段是考虑为以后预留扩展
--------------------------------------------------------------------------------------------------------------------------------------------------------
概要设计
1. 同时实现ReadableDataSource、WritableDataSource
其中读数据源用于构造时从数据库读取规则数据,仅加载一次;写数据用于控制台界面配置规则后将数据写回数据库。
2. 用一个抽象类WxAbstractJdbcDataSource封装公共逻辑,3种不同规则特殊部分在子类实现
3. 通过应用名称、ip、端口来构造一个数据源,便于使用
--------------------------------------------------------------------------------------------------------------------------------------------------------
详细解析
WxAbstractJdbcDataSource类:
ReadableDataSource<S, T>的S具体为List<Map<String, Object>类型,考虑用sql语句从数据库表查询,先将结果转换为List<Map<String, Object>类型
通过静态变量定义了3行sql模板语句,分别表示:
1. FIND_APP_ID_SQL:通过应用名称、ip、端口查询app_id // 以后通过app_id查询规则表的数据
2. READ_RULE_SQL:通过app_id查询规则表数据 // 注意因为转换成List<Map<String, Object>,这里用的SELECT *查询所有字段,避免了不同规则表结构不同问题;当然SELET里的字段名称,也可考虑在子类实现
3. DELETE_RULE_SQL:通过app_id删除规则表数据 // 写回数据到数据库暂时用的先删除后新增的方式
跟sentinel-datasource-extension包的AbstractDataSource一样,用SentinelProperty<T> property,在构造数中this.property = new DynamicSentinelProperty<T>();
使用javax.sql.DataSource存储MySQL的数据源,通过它可以获取JDBCConnection,接着可以使用JDBC API来查询、编辑数据,这里变量名用dbDataSource表示是数据库的数据源,跟sentinel的DataSource语义上区分;
appId存储通过appName、ip、port查询出的app_id,便于以后查询;
ruleTableName用于存储具体规则表名,通过abstract protected String initRuleTableName();赋值,在具体规则子类实现;
refreshSec、refreshService跟AutoRefreshDataSource类似,用于轮询更新数据,目前实际使用仅构造时读取一次数据,refreshSec赋值为null不轮询;
来看构造函数:
构造函数:检查参数合法性、属性赋值,调initAppId()查询app_id,调loadData()第一次从数据库读取数据;
其中loadData方法,调loadConfig()得到T类型t,在通过getProperty().updateValue(t);
之前文章提到过:loadConfig()通过readSource()得到S,就是这里得List<Map<String, Object>>,再通过转换器接口Converter<S, T>转换为T;
考虑到再使用时方便类的构造,这里没有使用Converter<S, T>接口,将convert定义了一个抽象得方法,由子类实现;
共4个抽象方法由子类实现
1. 获取具体规则表名称
2. 将readSource查询出的List<Map<String, Object>转换为具体的List<Xxxrule>
3. 获取向具体规则表插入数据的sql语句
4. 获取向具体规则表插入数据的sql语句的具体参数列表
实现WritableDataSource的write方法:
因value中是该类型全部的规则数据,更新暂时采取的最简单的方式,先删除再插入;
通过sql语句查询和更新数据的几个方法:
private Object findObjectBySql(String sql, Object[] sqlParameters) // 查询某个字段,查询appId使用
private List<Map<String, Object>> findListMapBySql(String sql, Object[] sqlParameters) // 查询列表List<Map<String, Object>>,查询规则列表使用
private void deleteAndInsert(String deleteSql, Object[] deleteSqlParameters, String insertSql, List<Object[]> insertSqlParametersList) // 删除并插入数据,实现write方法将规则数据列表写回数据库使用
private void closeJdbcObjects(AutoCloseable ... autoCloseables) // 关闭JDBC相关资源
同时提供了几个从map中取值的方法:
getMapStringVal、getMapIntVal、getMapLongVal、getMapDoubleVal
来看下具体规则DataSource子类的实现,以流控规则为例,WxFlowJdbcDataSource类:
实现了父类的4个接口,实现跟规则表名、表结构相关,insert语句模板,转换sentinel对应的XxxRule等;
使用:
因为WxFlowJdbcDataSource同时实现了ReadableDataSource、WritableDataSource接口,所以register用构造好的对象即可。
--------------------------------------------------------------------------------------------------------------------------------------------------------
总结
1. 通过抽象WxAbstractDataSource,实现ReadableDataSource、WritableDataSource,具体跟数据库表结构相关的操作在子类实现;
2. 操作数据库用原生JDBC API和sql语句,没有引入其它依赖;
--------------------------------------------------------------------------------------------------------------------------------------------------------
问题
1. 实现write方法更新数据,目前是先删除再插入的方式数据量大可能有性能问题,并且先删除数据后,规则的创建时间丢失了,程序中也未取以前的创建时间处理
考虑未来先缓存原来规则数据,write前进行比较,只将增量变动数据写回数据库;
2. WxAbstractJdbcDataSource类findObjectBySql、findListMapBySql、deleteAndInsert、closeJdbcObjects、getMapStringVal、getMapIntVal、getMapLongVal
、getMapDoubleVal等方法,其实跟本类无关,属于dbuitls方法,可以抽象为单独的工具类;
3. 使用原生javax.sql.DataSource和JDBC API虽然没有额外的依赖,但这样需要简单封装下JDBC API的调用,效率以及事务问题需要考虑。
--------------------------------------------------------------------------------------------------------------------------------------------------------
参考
在生产环境中使用-Sentinel-控制台 https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel-控制台
Sentinel自定义DataSource实战 https://my.oschina.net/go4it/blog/1930472
[实战]扩展一个定制的sentinel JdbcDataSource的更多相关文章
- 利用jQuery来扩展一个瀑布流插件
简单了解jQuery.fn.extend() jQuery.fn.extend()函数用于为jQuery扩展一个或多个实例属性和方法(主要用于扩展方法). (截图来自jQuery文档) 为了更清晰 ...
- 转:如何制作一个定制的 PHP 基础 Docker 镜像(一)
原文来自于:http://open.daocloud.io/ru-he-zhi-zuo-yi-ge-ding-zhi-de-php-ji-chu-docker-jing-xiang/ 目标:准备一个定 ...
- 扩展一个boot的插件—tooltip&做一个基于boot的表达验证
在线演示 本地下载 (代码太多请查看原文) 加班,加班加班,我爱加班··· 我已经疯了,哦也. 这次发一个刚接触boot的时候用boot做的表单验证,我们扩展一下tooltip的插件,让他可以换颜色. ...
- 给easyui datebox扩展一个清空按钮
/** * 给时间框控件扩展一个清除的按钮 */ $.fn.datebox.defaults.cleanText = '清空'; (function ($) { var buttons = $.ext ...
- 给easyui datebox时间框控件扩展一个清空的实例
给easyui datebox扩展一个清空的实例 步骤一:拓展插件 /** * 给时间框控件扩展一个清除的按钮 */ $.fn.datebox.defaults.cleanText = '清空'; ( ...
- 3.2 Lucene实战:一个简单的小程序
在讲解Lucene索引和检索的原理之前,我们先来实战Lucene:一个简单的小程序! 一.索引小程序 首先,new一个java project,名字叫做LuceneIndex. 然后,在project ...
- 给easyui datebox扩展一个清空按钮,无侵入
/** * 给时间框控件扩展一个清除的按钮 */ $.fn.datebox.defaults.cleanText = '清空'; (function ($) { var buttons = $.ext ...
- Dapr 与 NestJs ,实战编写一个 Pub & Sub 装饰器
Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的.无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架.Dapr 确保开发人员专注 ...
- 实战开发一个Nginx扩展 (Nginx Module)
repo地址 https://github.com/wujunze/nginx-http-echo-module nginx_module_echo 使用echo指令输出一个字符串 Nginx 版本 ...
随机推荐
- 微信小程序上传图片更新图像
解决思路: 1. 调用wx.chooseImage 选择图片 2.wx.uploadFile 上传图片 3.调用后台接口进行修改操作 修改原来的头像 wx.chooseImage({ success: ...
- Java秒杀实战 (三)秒杀基本功能开发
转自:https://blog.csdn.net/qq_41305266/article/details/80991687 一.两次MD5 1. 用户端: PASS = MD5( 明文 + 固定 Sa ...
- python之atexit模块的使用
python atexit 模块定义了一个 register 函数,用于在 python 解释器中注册一个退出函数,这个函数在解释器正常终止时自动执行,一般用来做一些资源清理的操作. atexit 按 ...
- vue 之img的src是动态渲染时(即 :src=' ' )不显示 踩坑
问题: <img :src="item.image ? `../../assets/image/${item.image}` : ''" alt="image&qu ...
- opencv读取图像python和c++版本的结果不同
问题: 在读取同一张图像时,python读取的结果和c++读取的结果差异较大,测试图像中最大误差达到16. 原因: python的opencv采用的是4.1.1,c++采用的是3.1.0,在解析JPE ...
- etcd简单测试类java版
为了方便现场安装完了etcd集群后确认集群是否好用,简单写了个测试类,网上搜的有点乱还有些不能运行,在这里再整理一个能够直接运行的 1.我把etcd的API设成3版本了,调用使用的jetcd,功能挺多 ...
- sql 分页查询 (每次6行 )
-- 对比 数据 是否 相同 select * from [dbo].[ProjecrInfo] where Project_state='已审核' -- 查询 已经 审核 有多少数据 -- 每次 ...
- Caused by: com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@1483de4 -- timeout at awaitAvailable(
Caused by: com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire ...
- DTcmsV4.0分析学习——(3)URL重写
3.URL重写 3.1 控制流程 通过IHttpModule控制所有页面请求,具体流程如下 (1)真实路径可正常访问 (2)前台页面通过URL重写映射aspx目录,后台页面通过URL重写映射admin ...
- java Timer和TimerTask(简单的使用)
Timer 是一个定时工具 TimerTask 是一个实现了Runnable接口抽象类,代表可以被Timer执行的任务 (1)Timer.schedule(TimerTask task,Date ti ...