1 HighAvailableDataSource
HighAvailableDataSource 是通過(guò)對(duì)多個(gè)DataSource的管理,來(lái)實(shí)現(xiàn)高可用的一個(gè)數(shù)據(jù)源

內(nèi)部用ConcurrentHashMap來(lái)存儲(chǔ)DataSource,由于只有一個(gè)無(wú)參構(gòu)造函數(shù),只能自己管理ConcurrentHashMap然后set進(jìn)去
2初始化
初始化同樣是init(),簡(jiǎn)短了很多,在DataSource上封裝了HA必要的邏輯
public void init() {
if (inited) {
return;
}
synchronized (this) {
if (inited) {
return;
}
if (dataSourceMap == null || dataSourceMap.isEmpty()) {
poolUpdater.setIntervalSeconds(poolPurgeIntervalSeconds);
poolUpdater.setAllowEmptyPool(allowEmptyPoolWhenUpdate);
poolUpdater.init();
createNodeMap();
}
if (selector == null) {
setSelector(DataSourceSelectorEnum.RANDOM.getName());
}
if (dataSourceMap == null || dataSourceMap.isEmpty()) {
LOG.warn("There is NO DataSource available!!! Please check your configuration.");
}
inited = true;
}
}
看到用雙檢鎖保證執(zhí)行一次,假如 dataSourceMap 為空,啟動(dòng) Updater ,動(dòng)態(tài)更新 dataSourceMap
然后主要是定義了selector,控制datasource的路由,默認(rèn)是RANDOM,此處對(duì)標(biāo)負(fù)載均衡。
從工廠類中根據(jù)name生成Selector,然后初始化
public void setSelector(String name) {
DataSourceSelector selector = DataSourceSelectorFactory.getSelector(name, this);
if (selector != null) {
selector.init();
setDataSourceSelector(selector);
}
}
2 DataSourceSelector
DataSourceSelector有三個(gè)實(shí)現(xiàn),一個(gè)是RandomDataSourceSelector,NamedDataSourceSelector和StickyRandomDataSourceSelector,默認(rèn)是隨機(jī)的RandomDataSourceSelector,StickyRandomDataSourceSelector就是增加了線程綁定。
-
init()中主要調(diào)用了 loadProperties()和 initThreads()倆方法。
loadProperties 該方法會(huì)從傳入的 HighAvailableDataSource 中查找相關(guān)的配置信息,包括checkingIntervalSeconds 檢查間隔時(shí)間,recoveryIntervalSeconds 蘇醒間隔時(shí)間,validationSleepSeconds 驗(yàn)證睡眠時(shí)間,blacklistThreshold 黑名單閾值。- initThreads 根據(jù)配置初始化線程,這里主要涉及到兩條線程 validateThread & recoverThread 。
- validateThread 的實(shí)現(xiàn)類是RandomDataSourceValidateThread,就是一個(gè)繼承Runnable的線程,主要是檢查 dataSourceMap 中的 datasource 是否可用
public void run() {
while (true) {
if (selector != null) {
checkAllDataSources();
maintainBlacklist();
cleanup();
} else {
break;
}
sleepForNextValidation();
}
}
checkAllDataSources 檢查 datasource 是否正常,這里會(huì)根據(jù)檢查時(shí)間看是否需要跳過(guò),主要是根據(jù) checkingIntervalSeconds 來(lái)判斷,接著到了真正檢查的邏輯,他會(huì)先從 datasource 中獲取鏈接的信息,并新建一條鏈接,而非重 datasource 中獲取,然后使用這個(gè)鏈接執(zhí)行一條指令,在 MySQL 中是執(zhí)行 pingInternal 方法。
檢查上面的執(zhí)行檢查結(jié)果是否成功,假如成功,就從 blacklist 中移除,并重置 errorcounter ,假如不成功且失敗次數(shù)大于 blacklistThreshold 黑名單閾值,將其放入 blacklist 中,等待后續(xù)操作。
cleanup 根據(jù) successTimes , errorCounts 和 lastCheckTimes 來(lái)清理 datasource,將其移入 blacklist 中
recoverThread同樣是實(shí)現(xiàn)了Runnable的RandomDataSourceRecoverThread,主要主要是 tryOneDataSource 嘗試將 datasource 將其移出 blacklist 。檢查的邏輯和 validateThread 的 checkAllDataSources 基本一致,即嘗試啟動(dòng)一個(gè)新的鏈接檢查該數(shù)據(jù)源是否正常。
get()方法是調(diào)用方獲取連接時(shí),真正獲取到目標(biāo)Datasource的方法,主要先將黑名單的和 busy 的DataSource 移除,這里校驗(yàn)是否 busy ,只檢查改 DataSource 的 poolcount 是否 <= 0; 假如是就代表空閑連接為 0 。最后在 getRandomDataSource() 通過(guò) radom 函數(shù)求余獲取到真正的 DataSource