[實戰]擴展一個定製的sentinel JdbcDataSource

Sentinel是今年阿里開源的高可用防禦的流量管理框架。html

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

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

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

--------------------------------------------------------------------------------------------------------------------------------------------------------sql

[學習]sentinel中的DatatSource(一) ReadableDataSource數據庫

[學習]sentinel中的DatatSource(二) WritableDataSource緩存

前兩篇學習了sentinel中的ReadableDataSource、WritableDataSource,接着我們來嘗試用MySQL數據庫做存儲,擴展一個定製的sentinel JdbcDataSource。app

代碼參考: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

相關文章
相關標籤/搜索