zoukankan      html  css  js  c++  java
  • [实战]扩展一个定制的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

     

  • 相关阅读:
    python函数第4天(day 23)
    python函数第3天(day 22)
    python函数第2天(day 21)
    python函数第一天(day 20)
    opencv笔记一(Mat初始化及Mat传递)
    ubuntu上opencv源码安装
    ubuntu上显卡驱动安装——GeForce GTX 1080 Ti
    ubuntu上CUDA9.0和CUDNN7.0安装
    vscode配置opencv c++开发环境
    opencv中Mat的属性
  • 原文地址:https://www.cnblogs.com/cdfive2018/p/9667193.html
Copyright © 2011-2022 走看看