記一次第三方數據庫性能瓶頸優化方案

首先用一張圖說明一下各個系統直接的調用關係

系統詳細說明如下

系統A:框架使用springboot開發,對外提供http接口,數據通過RPC(這裏指HSF,以下統一用HSF)調用系統B

系統B:框架使用springboot開發,對外暴露HSF接口,數據通過HSF訪問系統C獲取

系統C:框架不明,對外支持HSF調用,最終獲取DB數據返回

問題描述

用戶訪問系統A中的一個訂單下載功能,數據大概在600條左右,在系統A中原方式是通過分頁查詢(每次查詢10條)查詢60多次數據庫在用戶端出現的問題如下圖

當時首先想到的問題是增加服務器的連接時間(連接時間改爲3分鐘),優化查詢(每次改爲查詢50條)

然而改完之後速度提升不是很明顯,而且還出現新的問題

1、超時問題依舊存在

2、有時文件可以下載,但是數據不全,有時少50條,有時少150條

出現這種情況的解決方案是在系統中加入大量的日誌排查原因,最終發現系統A在訪問系統B獲取的分頁數據,有時候有數據,有時候又沒有數據,只能在系統B中繼續跟蹤日誌排查,發現系統B在訪問系統C時有超時情況,當超時時系統返回的空數據。

系統C屬於第三方的系統,我們無法在其中做出優化,雖然系統C的負責人聲稱DB已經做了優化,性能較原來有十倍提升(反正我是不信的)

所有到目前爲止該下載功能還存在兩個問題

1、系統調用時間過長

2、系統可能數據不全

由於系統C沒有優化空間,對於這兩個問題我們分別給出了優化方案

方案一:使用多線程同時對分頁進行數據查詢

方案二:使用重試機制保證數據的完整(目前最多重試三次),當然這也沒法完全保證數據完整,但也不能無限去重試,否則又會導致tomcat或者nginx連接超時

雖然這不是完整方案,但也是目前情況下給出的可以實施的方案了,具體實現代碼如下

多線程並行使用的是java8提供的IntStream類實現,在系統A中實現

long start = System.currentTimeMillis();     
final List<OrderVo> synchronizedResult =Collections.synchronizedList(Lists.newArrayList());       
int totalPages = "獲取總頁碼數";
IntStream.range(2, totalPages+1).parallel().forEach(i->{
	orderQueryParam.setPageIndex(i);
	PageableList<OrderVo> subResult = queryPage(orderQueryParam);
	if (CollectionUtils.isNotEmpty(subResult.getList())) {
		synchronizedResult.addAll(subResult.getList());
	}
});
log.info("queryPage result use {}ms", System.currentTimeMillis()-start);

查詢數據重試代碼在系統B中實現,代碼如下

//傳入isRetry控制查詢是否需要重試:DEFAULT_RETRY=3
int retry =isRetry ? DEFAULT_RETRY : 1;
PagerList<Order> pagerList =null;
while(retry-->0) {
	try {
		pagerList = systemCService.listOrders(params);
		if(pagerList != null && CollectionUtils.isNotEmpty(pagerList.getDatas())) {
			break;
		}
	}catch(Exception e) {
		log.error("queryPage error :",e);
	}
}

ok,代碼設計完成,在預發測試,測試結果:600多條數據用時30多秒(優化前nginx設置3分鐘依舊超時),數據與查詢出來的數據條數一致,問題算是解決。

但這種方案又有新的問題產生

1、使用多線程訪問系統C是否有風險,系統C是否會出現壓力過大導致系統宕機等問題

2、多線程異步查詢出的數據和在頁面看到的數據順序不一致

對於這兩個問題暫時先保留,後續繼續給出方案吧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章