處理億級數據的“定時任務”,如何縮短執行時間?


 

繼續答水友提問。

問題抽象:(1)用戶會員系統;(2)用戶會有分數流水,每個月要做一次分數統計,對不同分數等級的會員做不同業務處理;

 

數據假設

(1)假設用戶在100w級別;

(2)假設用戶日均1條流水,也就是說日增流水數據量在100W級別,月新增流水在3kW級別,3個月流水數據量在億級別; 

 

常見解決方案:用一個定時任務,每個月的第一天計算一次。

//(1)查詢出所有用戶

uids[] = select uid from t_user;

//(2)遍歷每個用戶

foreach $uid in uids[]{

         //(3)查詢用戶3個月內分數流水

         scores[]= select score from t_flow

                   where uid=$uid and time=[3個月內];

         //(4)遍歷分數流水

         foreach $score in scores[]{

                   //(5)計算總分數

                   sum+= $score;

         }

         //(6)根據分數做業務處理

         switch(sum)

         升級降級,發優惠券,發獎勵;

}

一個月執行一次的定時任務,會存在什么問題?

計算量很大,處理的數據量很大,耗時很久,按照水友的說法,需要1-2天。

畫外音:外層循環100W級別用戶;內層循環9kW級別流水;業務處理需要10幾次數據庫交互。 

 

可不可以多線程並行處理?

可以,每個用戶的流水處理不耦合。 

 

改為多線程並行處理,例如按照用戶拆分,會存在什么問題?

每個線程都要訪問數據庫做業務處理,數據庫有可能扛不住。 

這類問題的優化方向是:(1)同一份數據,減少重復計算次數;(2)分攤CPU計算時間,盡量分散處理,而不是集中處理;(3)減少單次計算數據量;

 

如何減少同一份數據,重復計算次數?

如上圖,假設每一個方格是1個月的分數流水數據(約3kW)。

 

 3月底計算時,要查詢並計算1月,2月,3月三個月的9kW數據;

4月底計算時,要查詢並計算2月,3月,4月三個月的9kW數據;

… 會發現,2月和3月的數據(粉色部分),被重復查詢和計算了多次。

畫外音:該業務,每個月的數據會被計算3次。

 

新增月積分流水匯總表,每次只計算當月增量

flow_month_sum(month, uid, flow_sum)

(1)每到月底,只計算當月分數,數據量減少到1/3,耗時也減少到1/3;

(2)同時,把前2個月流水加和,就能得到最近3個月總分數(這個動作幾乎不花時間);

畫外音:該表的數量級和用戶表數據量一致,100w級別。

這樣一來,每條分數流水只會被計算一次。

 

如何分攤CPU計算時間,減少單次計算數據量呢?

業務需求是一個月重新計算一次分數,但一個月集中計算,數據量太大,耗時太久,可以將計算分攤到每天。

如上圖,月積分流水匯總表,升級為,日積分流水匯總表。
把每月1次集中計算,分攤為30次分散計算,每次計算數據量減少到1/30,就只需要花幾十分鍾處理了。

甚至,每一個小時計算一次,每次計算數據量又能減少到1/24,每次就只需要花幾分鍾處理了。

 雖然時間縮短了,但畢竟是定時任務,能不能實時計算分數流水呢?

每天只新增100w分數流水,完全可以實時累加計算“日積分流水匯總”。

 

 使用DTS(或者canal)增加一個分數流水表的監聽,當用戶的分數變化時,實時進行日分數流水累加,將1小時一次的定時任務計算,均勻分攤到“每時每刻”,每天新增100w流水,數據庫寫壓力每秒鍾10多次,完全扛得住。

畫外音:如果不能使用DTS/canal,可以使用MQ。

 總結,對於這類一次性集中處理大量數據的定時任務,優化思路是:

(1)同一份數據,減少重復計算次數;

(2)分攤CPU計算時間,盡量分散處理(甚至可以實時),而不是集中處理;

(3)減少單次計算數據量; 希望大家有所啟示,思路比結論重要。

 

課后作業:假設,某系統登錄日志(日志比數據庫更難,數據庫可以建索引檢索)如下:

2019-08-15 23:11:15 uid=123 action=login

2019-08-15 23:11:18 uid=234 action=logout

求,2019-8-15這一天,系統同時在線用戶數曲線,精確到秒。 

說明:

(1)action只能為login/logout;

(2)在線用戶的定義為,已經login,還沒有logout,正在使用系統的用戶;

(3)8-15之前登錄,8-15還沒有登出的用戶,也算當天在線用戶(潛台詞是,只掃描當天的日志是不夠的);

 

轉自:https://mp.weixin.qq.com/s/aN-M8YcwXNE462HaVrQ6ig

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM