誰說ODS層就是簡單的數據同步?
本文轉載自微信公眾號「大數據技術與數倉」,作者西貝。轉載本文請聯系大數據技術與數倉公眾號。
ODS層辨析
ODS全稱是Operational Data Store,即操作數據存儲。
Inmon VS Kimball
Bill.Inmon的定義:ODS是一個面向主題的、集成的、可變的、當前的細節數據集合,用于支持企業對于即時性的、操作性的、集成的全體信息的需求。常常被作為數據倉庫的過渡,也是數據倉庫項目的可選項之一。
而Kimball的定義:操作型系統的集成,用于當前、歷史以及其它細節查詢(業務系統的一部分);為決策支持提供當前細節數據(數據倉庫的一部分)。
ODS VS DB VS EDW
ODS是用于支持企業日常的全局應用的數據集合,ODS的數據具有面向主題、集成的、可變的以及數據是當前的或是接近當前的特點。同樣也可以看出ODS是介于DB和DW之間的一種過渡存儲。
值得注意的是,Kimball所說的ODS是物理落地關系型數據庫中,但是在實際生產應用中,ODS往往是物理落地在數據倉庫中,比如Hive。
通常來說ODS是在數據倉庫中存儲業務系統源數據,所以從數據粒度、數據結構、數據關系等各個方面都與業務系統的數據源保持一致。但是,也不能僅僅將ODS層看做是業務系統數據源的一個簡單備份,ODS和業務系統數據源的差異主要是由于兩者之間面向業務需求是不同的,業務系統是面向多并發讀寫同時有需要滿足數據的一致性,而ODS數據通常是面向數據報表等批量數據查詢需求。
ODS層的設計思路
ODS層數據同步
上文提到ODS的數據來源于業務系統,且ODS落地的系統通常和業務系統是不同的,比如常見的將數據落到Hive中。所以,首先我們就需要將業務系統的數據抽取到ODS表中。一般來說,數據同步的方式大概可以分為三大類:文件抽取、數據庫表的抽取和原始日志的抽取。
文件抽取
通常情況下,ODS層表的存儲位置與業務系統表的存儲位置是不一樣的,比如業務表存在MySQL中,而ODS層存儲在Hive中。另外,有的時候,ODS層需要對接多個不同類型的業務系統庫,比如DB2、Oracle、Mysql等等,一種比較簡單實用的做法是和各個業務系統約定好數據接口,并讓業務系統按照數據接口格式生成數據文件和完結標示文件給到ODS。
這種方式有兩個明顯的優勢:一方面可以降低ODS處理多種類型數據庫系統能力需求,另一方面也減少了對業務系統的性能影響。但是這種方式也存在一些不足:數據的抽取過程和加載過程是分開的,由業務系統和ODS分別負責,同時接口新增和變更比較麻煩,需要較大的溝通維護成本,另外,數據落地到文件增加了額外的上傳下載工作,會造成效率比較低。
在實際的生產過程中,這種方式的數據同步也很少被使用。
直連同步
直連同步是指通過定義好的規范接口API和基于動態鏈接庫的方式直接連接業務庫,比如ODBC/JDBC等規定了統一的標準接口,不同的數據庫基于這套標準提供規范的驅動,從而支持完全相同的函數調用和SQL實現。比如經常使用的Sqoop就是采取這種方式進行批量數據同步的。
直連同步的方式配置十分簡單,很容易上手操作,比較適合操作型業務系統的數據同步,但是會存在以下問題:
- 數據同步時間:隨著業務規模的增長,數據同步花費的時間會越來越長,無法滿足下游數倉生產的時間要求。
- 性能瓶頸:直連數據庫查詢數據,對數據庫影響非常大,容易造成慢查詢,如果業務庫沒有采取主備策略,則會影響業務線上的正常服務,如果采取了主備策略,雖然可以避免對業務系統的性能影響,但當數據量較大時,性能依然會很差。
- 抽取增量數據需要依靠修改業務系統,新增時間戳字段,并且按時間戳增量抽取的數據準確性不能得到保障,業務系統做數據補丁不更新時間戳字段將會導致漏數;
- 實時性差,只能在某個時刻抽取數據,不能滿足準實時數據需求;
在實際的生產過程中,這種方式的數據同步經常被使用,值得注意的是:數據庫直連抽取比較適用于小批量表的數據抽取,對于大批量的數據而言,性能會比較差。
日志解析
據庫日志抽取是指通過分析數據庫日志,將業務系統的DDL和DML語句在一個鏡像系統還原,并通過數據流的方式對外提供實時數據服務。
所謂日志解析,即解析數據庫的變更日志,比如MySQL的Binlog日志,Oracle的歸檔日志文件。通過讀取這些日志信息,收集變化的數據并將其解析到目標存儲中即可完成數據的實時同步。這種讀操作是在操作系統層面完成的,不需要通過數據庫,因此不會給源數據庫帶來性能上的瓶頸。
由于是數據庫日志抽取是獲取所有的變更記錄,落地到ODS表的時候我們需要根據主鍵去重按照日志時間倒排序獲取最后狀態的變化情況。通常使FULL OUTER JOIN全外連接的方式進行Merge數據。
數據庫日志解析的同步方式可以實現實時與準實時的同步,延遲可以控制在毫秒級別的,其最大的優勢就是性能好、效率高,不會對源數據庫造成影響,目前,從業務系統到數據倉庫中的實時增量同步,廣泛采取這種方式。
當然,任何方式都不是完美的,使用日志解析的方式進行數據同步也會存在一些已知的問題:比如在業務系統做批量補數時會造成數據更新量超過處理的能力,從而導致數據延遲。另外,這種方式需要額外補數一個實時抽取的系統,從而也增加了投入和處理的復雜性。
該如何選擇同步方式
在實際的生產環境中,直連同步和日志解析是非常普遍的兩種數據同步方式,隨著實時技術的發展,使得實時數據同步的方式變得越來越方便,越來越多的企業開始嘗試使用日志解析的方式進行數據同步。這里需要注意的是,每種方式都有其優缺點及適用的場景,找到合適的方式就是最好的方式,切不可一味的追求狂拽酷炫的同步技術,這也是很多技術人員經常犯的錯誤,應用和鉆研新技術是技術人的追求,但是過猶不及,在解決具體問題的時候,要多方面權衡。
另外,數倉的建設是為業務服務的,應該把時間和精力放在如何支持業務、如何發揮數倉的價值、如何用數據為業務提供支持決策上來。筆者認為,數倉的建設不是一堆大數據技術的簡單堆砌,深入理解業務和數據才是數倉建設的第一要義。
ODS層數據清洗
關于ODS層是否做數據清洗一直是存在爭議的,但有一點是可以確定的,對于比較重的清洗工作是要留到后面數倉的ETL過程中進行處理。
但是,有這么一種情況:我們在長期的生產實際過程中,發現部分已知的數據問題的處理可以通過自動化的方式來處理,這種方式通常在數據入庫之前,做額外的加工處理后再做入庫操作。
數據清洗的主要工作是處理那些不符合要求的數據,從而提升數據質量,比如一些常見的問題:錯誤的數據、重復的數據
- 錯誤的數據
這種錯誤通常是業務系統處理不夠健全造成的,比如字符串數據后面有回車空格、日期格式不正確、日期越界等等,這些問題如果不在ODS層做處理,后續的解析處理過程中也是要留意處理的
- 重復的數據
例如,一些前端系統遷移過后的新老表融合可能會存在大量的重復歷史數據,這也可以在數據清洗這一步驟中完成消除重復數據的操作。需要注意的是,在數據清洗后還需要對ODS的數據做稽核,還需要對臟數據做稽核校驗,臟數據的校驗主要集中在數據量上,如果數據量波動特別大則需要人工介入處理。
其實,在大多數的情況下,是不需要做數據清洗處理的,可以把這個清洗環節放到后面的明細層ETL中進行處理。
ODS層表設計
通常而言,ODS層表跟業務系統保持一致,但又不完全等同于業務系統。在設計ODS物理表時,在表命名、數據存儲等方面都需要遵循一定的準則。
命名
比如:不管是表命名還是字段命名盡量和業務系統保持一致,但是需要通過額外的標識來區分增量和全量表,”_delta”來標識該表為增量表。
存儲
另外,為了滿足歷史數據分析需求,我們需要在ODS表中加一個時間維度,這個維度通常在ODS表中作為分區字段。如果是增量存儲,則可以按天為單位使用業務日期作為分區,每個分區存放日增量的業務數據。如果是全量存儲,只可以按天為單位使用業務日期作為分區,每個分區存儲截止到當前業務時間的全量快照數據。
ODS層常見的問題
實時和準實時數據需求、數據飄移處理、巨型數據量表處理、如何有效控制數據存儲。
實時性
實時數據倉庫的主要思想就是:在數據倉庫中,將保存的數據分為兩類,一種為靜態數據,一種為動態數據,靜態數據滿足用戶的查詢分析要求;而動態數據就是為了適應實時性,數據源中發生的更新可以立刻傳送到數據倉庫的動態數據中,再經過響應的轉換,滿足實時的要求。
由于實時處理的特殊性及復雜性,很多情況下實時分析是建立在ODS上而不是數據倉庫上,因為ODS處理邏輯簡單,數據鏈路相對較短,產出更快。
根據表的刷新頻率,可以將ODS層的表分為三大類:
- 實時ODS
接近實時地與業務庫的數據保持同步刷新,主要用于實時分析計算,比如實時的反欺詐,天貓雙11實時大屏等等。這類表的ETL是實時進行的,一般情況下,這類表會存儲在消息中間件中,比如Kafka,指的注意的是:要求涉及的業務過程不能過多,處理的業務邏輯不能過于復雜。這類ODS的表一般只是用于實時計算,相比批處理的表而言,其維護成本是相對較高的。
- 準實時ODS
例如15分鐘到1小時刷新一次,這類ODS比實時ODS成本要低些,基本可以滿足大部分的準實時需求。并且可以根據實際需求調整刷新頻率,具有較好的靈活性。在做處理這類準實時的ODS表時,需要特別注意ETL任務的產出效率,通常這類任務的產出時間最多不能超過ODS表的刷新周期時間。例如小時級別的表,任務不能超過1個小時。
- 傳統ODS
這是離線數倉最常見的一種表,即T+1,其數據一天刷新一次,可以利用業務系統的空閑時間進行刷新(通常是每天凌晨0-2點),可實現所有業務系統的數據集成和刷新。刷新頻率的下降也給系統有更多的時間進行數據更正和清洗。該類ODS層的表是最容易維護的。
數據漂移
所謂數據漂移,指的是這樣一種現象:ODS表的同一個業務日期數據中包含前一天或后一天凌晨附近的數據或者丟失當天的變更數據。
由于ODS需要承接面向歷史的細節數據查詢需求,這就需要物理落地到數據倉庫的ODS表按時間段來切分進行分區存儲,通常的做法是按某些時間戳字段來切分,實際往往由于時間戳字段的準確性問題導致數據飄移問題的發生。
一般情況下,我們使用的時間戳分為三類:
- 數據庫表中用來標示數據記錄更新的時間戳字段(即數據記錄的update時間,如modified_time)
- 數據庫日志中標示數據記錄的更新時間的時間戳字段(如log_time)
- 數據庫表中的用來記錄具體業務過程的發生時間(如proc_time)
在實際的生產過程中,以上三個時間戳往往會存在差異:比如由于網絡或者系統壓力問題,log_time或者modified_time會晚于proc_time。
當時用數據庫記錄更新時間或者數據庫日志更新時間進行切分數據分區時,有可能會導致凌晨時間產生的數據記錄漂移到后一天,如果使用業務時間進行限制,則會遺漏很多其他過程的變化記錄。
那么,該如何解決上述的問題呢?常見的方式有兩種:
- 多冗余數據
基本原則是寧多勿少,即ODS每個時間分區中向前向后都多冗余一些數據,具體的數據切分讓下游根據自身不同的業務場景根據不同的業務時間proc_time來限制。這種情況同樣也會存在一些誤差:比如一個訂單是在6.1日支付的,但在6.2號凌晨申請退款關閉了該條訂單,那該條訂單記錄就會被更新,下游再統計支付訂單狀態時會錯誤統計。
- 多個時間戳字段限制時間來獲取相對準確的數據
- 首先確保數據不遺漏,根據log_time分別冗余前一天最后15分鐘的數據和后一天凌晨開始15分鐘的數據,并用modified_time過濾非當天數據,此時會過濾掉一部分后一天凌晨開始15分鐘的數據,但是還是會冗余一部分前一天的數據,由于log數據保存了多個狀態的數據,所以還需要根據log_time進行降序排列,獲取最新狀態的記錄,這樣就去掉了中間狀態的數據。
- 下一步就是處理漂移到后一天的數據,根據log_time取后一天的15分鐘數據;針對此數據,按照主鍵根據log_time作升序排列去重。因為我們需要獲取的最接近當天記錄變化情況(數據庫日志數據將保留所有變化的數據,但是落地到ODS的表是需要根據主鍵去重獲取最后狀態的變化情況),這樣就會把漂移到后一天的最初狀態的數據篩選出來了。
- 最后將前兩步的結果數據作全外連接,限定業務時間proc_time來獲取我們需要的數據
數據存儲
- 避免重復抽取數據,
這種情況在中小公司基本上不會存在,但是在大型的集團公司,不同的數據團隊負責不同的數據集市或者業務,會存在重復同步數據源的情況,解決這類問題的首要措施不是技術上而是管理上的,必須建立統一的ODS層,收攏權限,由專門的團隊統一管控。
- 表的生命周期管理
一般而言,全量表保存3~7天,增量表要永久保存
- 無下游任務的表
比如一些表上源表不產生數據了,或者該表沒有被下游任務使用,這種情況下要及時下線同步任務,避免造成資源的浪費。