工作中需要同步一些資料,大概接近百萬條的量級,更新時間非常慢,需要7個多小時,更新的頻率是每週一次。隨著資料量的一步步增加,時間也越來越多,逐漸成為乙個風險因子,於是想到要嘗試做一些優化,降低同步時間。
經過調查,需要同步的是table_a,同步的過程可以簡化表述為兩步:
call api_b to get updated value.
update records in db.
首先,檢查log,看看這兩個過程分別耗時多少。分析生產環境的log,發現,對於一條資料,
做乙個計算,100萬條資料,假設每條同步需要0.4s,那麼總耗時就是100h,和實際的6h不符。經過思考後解釋是:還需要考慮執行緒和冗餘資料。
實際使用了乙個大小為10的執行緒池,100h除以10的話,就是10h,再算上一些冗餘的不需要更新的資料(估計20%左右),理論計算時間和實際時間是在乙個數量級上的。
所以,可以從兩個方面著手優化,一是優化呼叫api的時間,二是優化db寫資料的時間。
分析api呼叫的**,看到是一條一條呼叫的,使用了object callapi(object input)
這個函式。首先,做乙個壓力測試,看下callapi()
這個方法每秒可以處理多少請求。
executorservice executor = executors.newfixedthreadpool(100);
for (int i=0; i<100; i++)
開100個執行緒,每個執行緒請求100次,總計10000個request。根據總耗時,計算出callapi()
可以處理請求約50個/秒。這個速度顯然已經滿足不了我們的系統了。
聯絡上游api開發部門,經過協商,短期來看,可以為我們配置單獨的機器來提高生產環境的query速度。從長遠來看,
不難猜想到,db也是一條一條呼叫更新的。優化的策略是batch update。
以下是模擬測試db update的部分,單次更新:
@test
public void updateonebyone()
@override
public int getbatchsize()
}); return updatecounts;
}
spring xml config:
測試的結果是:對於500條資料,單次更新耗時370s,批量更新耗時9s。批量更新快了約40倍。
這裡的乙個坑是:不同資料庫,比如生產環境v.s.開發環境,有可能性能表現是不一樣的。比如上面的(簡化後的)例子是在開發環境下的測試結果,1條資料單次更新大概耗時1.3s,而在生產環境的實際資料是20ms。這時候做優化需要找準baseline,不然搞半天發現用了新方法竟然還比生產環境的舊方法慢,其實是開發的資料庫本身相對更慢而已。
最終,解決的方案是:一方面,聯絡上游api部門開發新介面。另一方面,使用batch update優化db寫入。
在解決這個問題的過程中,還看了許多其它的文章,有一篇談到了oracle改進sql,update之前先做乙個排序,讓資料盡可能靠近。(oracle大資料量更新方法)
另外,還看了一篇,講到了修改rewritebatchedstatements
引數,解決spring jdbctemplate batch update無效的問題。(jdbctemplate.batchupdate批量執行效能差解決)
雖然最終看下來和本題無關,但還是挺有收穫的。
記錄一次大量CLOSE WAIT的情況
近期的專案中,有乙個特殊的需求,對於每個客戶端程式有若干個機構,對於每個機構有不同的客戶端證書,程式間隔一段時間向服務端進行請求,根據請求的成功與否更新各機構的狀態 如正常,證書未配置,證書過期等 實際投入測試環境進行使用的時候,執行了一段時間之後,客戶端程式出現了大量的close wait的情況,...
運維老鳥曾經的一次大資料遷移感慨回顧
運維老鳥曾經的一次大資料遷移感慨回顧 5年前的一次大資料區域網內遷移,約10多個t小檔案資料!今天備課架構師課程偶然看到了這個感慨,和大家分享下!這是當初pk各個部門和cto力薦我的這個方案 結果遇到難點了!當年感慨原文 熬了一天兩夜。功夫不負有心人啊 終於搞定了所有問題,現在萬事具備 只差最後切換...
運維老鳥曾經的一次大資料遷移感慨回顧
運維老鳥曾經的一次大資料遷移感慨回顧 5年前的一次大資料區域網內遷移,約10多個t小檔案資料!今天備課架構師課程偶然看到了這個感慨,和大家分享下!這是當初pk各個部門和cto力薦我的這個方案 結果遇到難點了!當年感慨原文 熬了一天兩夜。功夫不負有心人啊 終於搞定了所有問題,現在萬事具備 只差最後切換...