《大數(shù)據(jù)之路》一書中對數(shù)據(jù)漂移的處理是這么說的:
數(shù)據(jù)漂移的處理
通常我們把從源系統(tǒng)同步進人數(shù)據(jù)倉庫的第一層數(shù)據(jù)稱為 ODS或者staging 層數(shù)據(jù)募强,阿里巴巴統(tǒng)稱為 ODS 。數(shù)據(jù)漂移是 ODS 數(shù)據(jù)的一個頑疾重父,通常是指 ODS 表的同一個業(yè)務日期數(shù)據(jù)中包含前一天或后凌晨附近的數(shù)據(jù)或者丟失當天的變更數(shù)據(jù)。
由于 ODS 需要承接面向歷史的細節(jié)數(shù)據(jù)查詢需求毅整,這就需要物理落地到數(shù)據(jù)倉庫的 ODS 表按時間段來切分進行分區(qū)存儲 映胁,通常的做法是按某些時間戳字段來切分预侯,而實際上往往由于時間戳字段的準確性問題導致發(fā)生數(shù)據(jù)漂移致开。
通常,時間戳字段分為四類:
- 數(shù)據(jù)庫表中用來標識數(shù)據(jù)記錄更新時間的時間戳字段(假設這類字段叫 modified time )雌桑。
- 數(shù)據(jù)庫日志中用來標識數(shù)據(jù)記錄更新時間的時間戳字段·(假設這類宇段叫 log_time)喇喉。
- 數(shù)據(jù)庫表中用來記錄具體業(yè)務過程發(fā)生時間的時間戳字段 (假設這類字段叫 proc_time)祖今。
- 標識數(shù)據(jù)記錄被抽取到時間的時間戳字段(假設這類字段extract time)校坑。
理論上,這幾個時間應該是 致的千诬,但是在實際生產(chǎn)中耍目,這幾個時間往往會出現(xiàn)差異,可能的原因有以下幾點:
- 由于數(shù)據(jù)抽取是需要時間的徐绑, extract_time 往往會晚于前三個時間邪驮。
- 前臺業(yè)務系統(tǒng)手工訂正數(shù)據(jù)時未更新 modified_time
- 由于網(wǎng)絡或者系統(tǒng)壓力問題, log_time 或者 modified_time 會晚proc_time傲茄。
通常的做法是根據(jù)其中的某 個字段來切分 ODS 表毅访,這就導致產(chǎn)生數(shù)據(jù)漂移。下面我們來具體看下數(shù)據(jù)漂移的幾種場景盘榨。
- 根據(jù) extract_time 來獲取數(shù)據(jù)喻粹。這種情況數(shù)據(jù)漂移的問題最明顯
- 根據(jù) modified_time 限制。在實際生產(chǎn)中這種情況最常見草巡,但是往往會發(fā)生不更新 modified time 而導致的數(shù)據(jù)遺漏守呜,或者凌晨時間產(chǎn)生的數(shù)據(jù)記錄漂移到后天。根據(jù) log_time 限制山憨。由于網(wǎng)絡或者系統(tǒng)壓力問題查乒, log_time 會晚proc_time ,從而導致凌晨時間產(chǎn)生的數(shù)據(jù)記錄漂移到后一天郁竟。
例如玛迄,在淘寶“雙 11 ”大促期間凌晨時間產(chǎn)生的數(shù)據(jù)量非常大,用戶支付需要調用多個接口棚亩,從而導致 log time 晚于實際的支付時間蓖议。 - 根據(jù) proc_time 限制。僅僅根據(jù) proc_time 限制蔑舞,我們所獲取的ODS 表只是包含一個業(yè)務過程所產(chǎn)生的記 拒担,會遺漏很多其他過程的變化記錄,這違背了 ODS 和業(yè)務系統(tǒng)保持 致的設計原則攻询。
處理方法主要有以下兩種:
( 1)多獲取后 天的數(shù)據(jù)既然很難解決數(shù)據(jù)漂移的問題从撼,那么就在 ODS 每個時間分區(qū)中向前、向后多冗余 些數(shù)據(jù),保障數(shù)據(jù)只會多不會少低零,而具體的數(shù)據(jù)切分讓下游根據(jù)自身不同的業(yè)務場景用不同的業(yè)務時間 proc time 來限制但是這種方式會有一些數(shù)據(jù)誤差婆翔,例如 個訂單是當天支付的,但是第天凌晨申請退款關閉了該訂單掏婶,那么這條記錄的訂單狀態(tài)會被更新啃奴,下游在統(tǒng)計支付訂單狀態(tài)時會出現(xiàn)錯誤。
( 2)通過多個時間戳字段限制時間來獲取相對準確的數(shù)據(jù)
- 首先根據(jù) log_time 分別冗余前一天最后 15 分鐘的數(shù)據(jù)和后一天凌晨開始 15 分鐘的數(shù)據(jù)雄妥,并用 modified time 過濾非當天數(shù)據(jù)最蕾,
確保數(shù)據(jù)不會因為系統(tǒng)問題而遺漏。 - 然后根據(jù) log_time 獲取后一天 15 分鐘的數(shù)據(jù) 針對此數(shù)據(jù)老厌,按照主鍵根據(jù) log_time 做升序排列去重瘟则。因為我們需要獲取的是最
接近當天記錄變化的數(shù)據(jù)(數(shù)據(jù)庫日志將保留所有變化的數(shù)據(jù),但是落地到 DS 表的是根據(jù)主鍵去重獲取最后狀態(tài)變化的數(shù)據(jù))枝秤。 - 最后將前兩步的結果數(shù)據(jù)做全外連接醋拧,通過限制業(yè)務時間proc_time 來獲取我們所需要的數(shù)據(jù)。
下面來看處理淘寶交易訂單的數(shù)據(jù)漂移的實際案例淀弹。
我們在處理“雙 11”交易訂單時發(fā)現(xiàn)丹壕,有大批在11月11日23:59:59 左右支付的交易訂單漂移到了12日 。主要原因是用戶下單支
付后系統(tǒng)需要調用支付寶的接口而有所延遲薇溃,從而導致這些訂單最終生成的時間跨天了菌赖。即 modified_time和log_time 都晚于proc_time
如果訂單只有一個支付業(yè)務過程,則可以用支付時間來限制就能獲取到正確的數(shù)據(jù)痊焊。但是往往實際訂單有多個業(yè)務過程 下單盏袄、支付、成
功薄啥,每個業(yè)務過程都有相應的時間戳字段辕羽,并不只有支付數(shù)據(jù)會漂移。如果直接通過多獲取后 天的數(shù)據(jù)垄惧,然后限制這些時間刁愿,則可以獲
取到相關數(shù)據(jù),但是后 天的數(shù)據(jù)可能已經(jīng)更新多次到逊,我們直接獲取到的那條記錄已經(jīng)是更新多次后的狀態(tài)铣口,數(shù)據(jù)的準確性存在 定的問題。
因此觉壶,我們可以根據(jù)實際情況獲取后15分鐘的數(shù)據(jù)脑题,并限制個業(yè)務過程的時間戳字段(下單、支付铜靶、成功)都是“雙 ”當天的叔遂,然后對這些數(shù)據(jù)按照訂單的 modified_time 升序排列,獲取每個訂單首次數(shù)據(jù)變更的那條記錄。
此外已艰,我們可以根據(jù) log_time 分別冗余前 天最后15 分鐘的數(shù)據(jù)和后 天凌晨開始 15 分鐘的數(shù)據(jù)痊末,并用 modified_time 過濾非當天數(shù)據(jù),
針對每個訂單按照 log_time 進行降序排列 哩掺,取每個訂單當天最后一次數(shù)據(jù)變更的那條記錄凿叠。
最后將兩份數(shù)據(jù)根據(jù)訂單做全外連接,將漂移數(shù)據(jù)回補到當天數(shù)據(jù)中嚼吞。
==========================分割線==========================
上面講的比較晦澀盒件,例子由于沒有具體數(shù)據(jù)的支撐也比較難以理解。我憑著自己的理解和對實際數(shù)據(jù)的想象對上面的例子做一點解釋誊薄。
首先場景是在雙11當天的23:59:59時有大量支付訂單由于調用鏈路長以及網(wǎng)絡延遲等原因履恩,最終數(shù)據(jù)入庫的實際漂移到了12日锰茉。
在我理解這里面的數(shù)據(jù)應該是mysql庫的binlog日志呢蔫。
- proc_time:數(shù)據(jù)的產(chǎn)生的事件時間。不同的業(yè)務過程理解不同飒筑,支付的是支付時間片吊,下單的是下單時間。
- modified_time:數(shù)據(jù)更新時間协屡,不同的業(yè)務過程可能有多個狀態(tài)的數(shù)據(jù)俏脊,比如支付有待支付和已支付等狀態(tài)。
- log_time:binlog日志時間肤晓。
正常proc_time<log_time<modified_time
由于每個業(yè)務過程可能經(jīng)過很多狀態(tài)的變化爷贫,所以只獲取漂移后的第一個狀態(tài)數(shù)據(jù),因為有可能在后一天已經(jīng)對漂移的數(shù)據(jù)做了狀態(tài)變更過补憾。
主要分兩步操作:
1.獲取當天漂移的數(shù)據(jù)漫萄。獲取后一天15分鐘的數(shù)據(jù),限制業(yè)務過程時間戳proc_time=雙11盈匾,并按modified_time升序排序腾务,取第一條。
proc_time=雙11削饵,即獲取雙11漂移到12日的數(shù)據(jù)岩瘦,modified_time升序排序為了取第一條狀態(tài)的數(shù)據(jù)。
2.獲取當天未漂移的數(shù)據(jù)并剔除前一天漂移過來的數(shù)據(jù)窿撬。根據(jù) log_time 分別冗余前一天最后15 分鐘的數(shù)據(jù)和后一天凌晨開始15 分鐘的數(shù)據(jù)启昧,并用modified_time 過濾非當天數(shù)據(jù),針對每個訂單按照 log_time 進行降序排列 劈伴,取每個訂單當天最后一次數(shù)據(jù)變更的那條記錄密末。
分別冗余前一天最后15分鐘和后一天前15分鐘數(shù)據(jù),目的是考慮到有往前漂移的場景。
modified_time 過濾非當天數(shù)據(jù)苏遥,即modified_time饼拍!=雙11,過濾掉前后兩天的正常數(shù)據(jù)田炭。
log_time 降序排列 师抄,只取每個訂單當天最后一次數(shù)據(jù)變更。只取訂單當天即log_time=雙11教硫,剔除前一天漂移過來的數(shù)據(jù)叨吮。
最后對這兩部分數(shù)據(jù)做全外連接即得到當天所有的數(shù)據(jù)。