前言
我們是一個做傳統會員管理CRM的團隊,應用數據的級別比較高,過去會存在這樣一種現象,T+1 財務報表,運營統計各類報表 的指標偶爾會和商戶的自己記錄用戶消費儲值記錄會有出入,后來了解到,我們系統中存在很嚴重的數據漂移問題,這也是dw系統或者ods來說普遍存在的問題,今天我們好好聊下該如何解決數據漂移問題
數據漂移產生的原因
通常我們把從源系統同步進入數據倉庫的第一層數據成為ODS層數據,我們公司目前只有ODS一層,雖說只有一層,但是仍然有有一個頑疾:數據漂移,簡單來說就是ODS表的同一個業務日期數據中包含前一天或者后一天凌晨附近的數據或者丟失當天的變更數據。更新表來說會丟失變更數據,流水表一般會丟失上一天數據,或者說上一天數據漂移到下一天。
由於ODS需要承接面向歷史的細節數據查詢需求,這就是需要物理落地到數據倉庫的ODS表按時間段來進行分區存儲,通常的做法是按某些時間戳字段來切分,二實際上往往由於時間戳字段的准確性問題導致發生數據漂移。當然我們目前切分的字段是datetime類型的updatetime字段。
通常時間戳字段分為四類:
(1)數據庫表中用來表示數據記錄更新時間的時間戳字段(假設這類字段叫modified_time);
(2)數據庫日志中用來表示數據記錄更新時間的時間戳字段(假設這類字段叫log_time);
(3)數據庫表中用於記錄具體業務過程發生時間的時間戳字段(假設這類字段叫proc_time);
(4)標識數據記錄被抽取到時間的時間戳字段(假設這類字段叫extract_time)當然這種還是比較少用的;
理論上這幾個時間應該是一致的,但是在實際生產中,這幾個時間往往會出現差異,可能的原因有以下幾點:
(1)由於數據抽取是需要時間的,extract_time往往會萬余前三個時間。當然這個應用的必要場景我所料及的不多;
(2)前台業務系統手工訂正數據時候未更新modified_time,在我們的系統中這種現象仍然沒有杜絕;
(3)由於網絡或者系統壓力問題,log_time或者modified_time 會晚於proc_time;
通常的做法是根據其中的一個字段來切分ODS表,這就導致產生數據漂移,下面說下我所了解到數據漂移的幾種場景:
(1)根據extract_time來獲取數據。這種情況數據漂移的問題最明顯,當然實際生產中這種會發生在解析log的場景中,對於數據級別不高的分析業務來講有可能是可以接受的;
(2)根據modified_time限制。在實際生產中這種情況是最常見的,但是往往會發生不更新modified_time而導致的數據遺漏,或者凌晨時間產生的數據記錄漂移到后一天,這是我們實際生產中更新表會存在的漂移問題。
(3)根據log_time限制。由於網絡或者系統壓力問題,log_time會晚於proc_time,從而導致凌晨時間產生的數據記錄漂移到后一天。例如周末節假日我們所服務的很多餐飲商戶凌晨期間產生數據量還是比較大的,在掉我們收銀,點餐等行為會調用我們多個接口,從而導致log_time晚於實際的支付或者點餐時間。
(4)根據proc_time限制。僅僅根據proc_time限制,我們所獲取的ODS表只是包含一個業務過程所產生的記錄,會遺漏很多其他過程的變化記錄,這違背了ODS和業務系統保持一致的設計原則
解決方法
解決方法先談兩種主要的:
(1)多獲取后一天的數據
既然很難解決數據漂移的問題,那么就在ODS每個時間分區中向前、向后多冗余一些數據,保證數據只會多不會少,而具體的數據切分讓下游根據自身不同的業務場景用不同的業務時間proc_time來限制。但是這種方式會有一些數據誤差,例如一個訂單是當天支付的,但是第二天凌晨申請退款關閉了該訂單,那么這條記錄的訂單狀態會被更新,下游在統計支付訂單狀態時會出現錯誤。
(2)通過多個時間戳字段限制時間來獲取相對准確的數據
1> 首先根據log-time分別冗余前一天最后15分鍾的數據和后一天凌晨開始15分鍾數據,並用modified_time過濾非當天數據,確保數據不會因為系統問題而被遺漏
2>然后根據log_time獲取后一天15分鍾的數據;針對此數據按照主鍵根據log_time做升序排列去重,因為我們要獲取的是最接近當天記錄變化的數據(數據庫日志將保留所有變化的數據,但是落地到ODS表的是根據主鍵去重獲取的最后狀態的數據)
3>最后將前兩步結果數據做全外連接,通過限制業務時間proc_time來獲取我們所需要的數據
今天先到這里接下來還會補充我們具體解決的步驟;