探索流批一體結構下的實時數倉
|0x00 越來越高的時效性要求
在數據倉庫的建設過程裏,我們一直秉承着 “離線先行” 的方針,因爲離線的技術棧非常成熟,開發起來很快,同時監控工具也做的比較完善,出了問題能及時發現、及時處理。過去我們處理實時的需求,一般都會轉化爲準實時的模式,例如分鐘級調度,但畢竟它不是完全的實時模式,不過絕大多數情況下,應對業務訴求也是足夠了。
但隨着 Flink 爲代表的新一代框架的出現,很多業務已經不再滿足於做準實時的開發了,完全實時化的數據流、面向實時做的數倉設計,就成爲了數據和業務都關心的高價值項目。哪怕是沒有實時的訴求,我們也會盡量去搞一套體系出來,不僅是爲了趕時髦,也是爲了給自己儲備點未來的知識。實時化已經是大趨勢,儘管實時不能完全代替離線場景,但常規的業務模式全部實時化,還是沒有問題的。
但是,除了流量等場景,大部分複雜業務場景下,純實時搞不定需求,比如反作弊。於是我們傾向於用流批一體的架構來做,先把業務做起來,再用實時鏈路去提升數據的時效性。流批一體最著名的,就是 Lambda。Lambda 架構是由 Storm 的作者 Nathan Marz 提出的一個實時大數據處理框架。Marz 在 Twitter 工作期間開發了著名的實時大數據處理框架 Storm,Lambda 架構是其根據多年進行分佈式大數據系統的經驗總結提煉而成。Lambda 架構的目標是設計出一個能滿足實時大數據系統關鍵特性的架構,包括有:高容錯、低延時和可擴展等。
除此之外,Kappa 架構也是實時數倉的另一種方案,但是因爲實時架構用到的資源,通常都比較貴,因此完全的 Kappa 架構,目前應用的不會太多,很長一段時間內,Lambda 與 Kappa 兩種方案會同時存在。
當然,實時數倉受制於架構的影響,也不可避免的需要同時寫兩套代碼,而且因爲解析方式的不同,Flink SQL 難免要跟 Hive SQL 出現一些語法上的不一致,對於工程開發來講,“要了親命了”,我們在後面會專門討論這個問題。
不論怎樣,大數據處理的實時化,已經成爲了一個潮流,而 Flink 也成爲了實時計算行業的標準。
|0x01 數據計算、存儲與查詢引擎
實時數倉需要關心兩種架構,一種是數據處理的架構,另一種則是數據庫。
首先講數據處理架構,Flink 已經是實時計算行業事實上的標準。能夠將業務開發實時化,只是 Flink 的一個起點,Flink 最終的目的肯定是爲了給用戶提供徹底的實時離線一體化體驗。目前的流批方案存在一些比較明顯的
而業務實時化只是一個起點,Flink 的目標之一就是給用戶提供實時離線一體化的用戶體驗。其實很多用戶不僅需要實時的數據統計,爲了確認運營或產品的策略的效果,用戶同時還需要和歷史(昨天,甚至是去年的同期)數據比較。而從用戶的角度來看,原有的流、批獨立方案存在一些痛點:
第一,就是一套代碼,需要維護兩遍,不僅語法不通,處理數據的思路也不同,很容易出錯。
第二,就是數據處理鏈路冗餘,事實上從第二天開始,數據就跟離線沒什麼不同了,而實時的資源通常又很貴,所以資源是會產生浪費的。
第三,就是數據口徑不同,道理也很簡單,架構不同,就是很容易出錯。
Flink 應對的方式,就是一套引擎,多種方式。
首先是 SDK 層,如 Table/SQL,用戶的業務邏輯只要開發一遍,就可以同時在流和批的兩種場景下使用。
其次是執行引擎,提供了統一的 DAG,用來描述數據處理流程 Data Processing Pipeline。這個很關鍵,在業務邏輯執行前,都會先轉化爲 DAG 圖,再轉化成在分佈式環境下執行的 Task,以同時支持兩種 Shuffle 方式。
更多的內容,這裏不展開。
數據庫的選型,即 OLAP 怎麼搞,也是實時數倉另外一個關心的架構問題。過去海量數據的存儲與計算,都是數倉技術需要考慮的問題,但隨着技術的發展,不同形態的數據庫技術發展蓬勃,比如 ES、MongoDB、HBase、Kudu 等出現,存儲對於數據倉庫技術而言,已經不再是非常難以解決的問題了,那麼我們目前關心的,就是數據庫能否支持數據的高速寫入,以及能否實現高併發低延遲的查詢響應。
爲了能夠更好的理解這個問題,我們把問題抽象成如下幾個部分:
第一,高併發特性,目前的實時數據已經不再是給高管、運營看數的工具,隨着數據運營深入人心,外部的商家等人羣,都有訪問實時數據的訴求,那麼這時候高併發就是必須要考慮的問題。
第二,響應速度,大促變的越來越頻繁,同時移動端看數據的需求也變得越來越多,甚至算法也開始要實時的數據源,大家都希望能夠看到毫秒級的變化,也就是刷新一下頁面數據就會變,那麼數據庫的響應速度,就顯得非常重要了。
第三,處理時延,還是大促,我們需要考慮流量峯值下的數據處理能力,至少延遲不能增加太高。同時,實時數倉通常會帶來資源的錯峯計算,但其實隨着雲原生的普及,資源混布成爲常態,這個特性已經帶不來更多的收益了。
綜上,其實我們需要考慮的是一種能夠統籌 OLTP 和 OLAP 的數據庫,學名叫作線事務處理 / 在線分析處理( HTAP: Hybrid Transactional/Analytical Processing),以分佈式事務和水平彈性擴展爲主要賣點的產品。或者,我們可以把此類框架稱之爲 “數據湖” 產品,因爲我們的目標都是爲了實時的處理和分析數據。
TiDB,或者是阿里的 Hologres、ADB,都在朝着這條路去走。
但實時數據流處理有一個特殊的情況,即維表的處理,因爲在實時數倉中,事實與維度必須明確區分,因爲走的數據處理鏈路不同,而針對維度數據存儲的數據庫,就是 HBase,K-V 的查詢場景,在這裏依舊是一個強訴求。
因此,我們的架構設計,基本上可以統一在 Kafka + Flink + TiDB/HBase 這樣的方案上。當然,隨着未來技術不斷迭代,相信實時數倉架構,會像離線那樣完善起來,但這條路還需要走一段時間。當下的實時架構,很像當年離線蓬勃發展的情況。
|0x02 實時數倉的設計
回到本文的重心,實時數倉的設計,我們的思路依舊是遵循離線數倉的方式,即 ODS、DWD、DWS、DIM、ADS 進行區分。但不同的是,ODS 統一採用消息隊列來作爲方案設計,因此 ODS 面向多數據源的設計就會弱化。其他各個層上,主要功能與離線類似,但設計有所不同。
類似的地方,DWD 依舊作爲明細數據來處理,DWS 對數據域內數據做輕度彙總,ADS 面向需求場景做統一設計。
實時數倉的挑戰,主要體現在四個方面:
時效性挑戰:實時數倉如果延遲大了,那麼跟分鐘級計算就沒有本質區別,因此如何儘可能的快,就是實時數倉最大的挑戰;
準確性挑戰:離線數據有完整的質量保證體系,但這些在實時數倉還都是比較新的挑戰,過去我們通過流批一體解決了多數據源帶來的結果不一致性,但如果保證開發結果的準確,挑戰依舊很大;
穩定性挑戰:實時數倉與離線不同,數據計算過程中出現了錯誤,修補的成本非常高,甚至可能導致永久性的數據丟失;
靈活性挑戰:離線數倉最大的特點,就是可以應對海量需求的開發挑戰,而實時數倉一旦運行任務太多,不論對開發還是運維,挑戰都是很大的,尤其是面對需求頻繁變更的場景。
從數倉的規範上看,各層的變化如下:
ODS:由於流批一體統一了數據源,而且 ODS 原本就不對原始數據做處理,因此可以無需再建表,直接用數據源即可;
DWD:與離線類似,實時業務也需要構建事實明細表,但區別在於,離線方案中,我們爲了提高明細表的使用便捷程度,往往會把一些常用的維度退化到事實表,但實時方案出於時效性的考慮,傾向於不退化或者只退化不會變的維度,也就是 DWD 更類似於範式建模;
DWS:這一層根據業務情況的不同,在實時數倉的建設策略上,差異比較大;通常情況下,離線建設 DWS,是針對比較成熟的業務,將維度逐級上卷;這樣做能夠將邏輯進行收口,提高下游使用的複用率,但缺點就是做的比較厚重;如果實時業務不是那麼複雜,那麼就不建議將 DWS 建的很重;究其原因,彙總層的目的在於預計算、提升效率和保證指標的一致性,實時鏈路太長,容易造成高的延遲和比較大的資源消耗;
DIM:維表在實時計算中非常重要,也是重點維護的部分,維表需要實時更新,且下游基於最新的維表進行計算;
ADS:功能和用途不變。
在實際的開發過程中,數倉的分層設計,基於架構選擇的不同,其實還是有區別的。
例如,DWD/DWS 是基於事實進行統計,單業務過程,不帶維度,而 DIM 維度數據存儲在 HBase 中,在 ADS 層我們將兩者融合在一起,進行計算。但如果考慮到維表更新的問題,那麼其實 ADS 可能就不會存在,而是以視圖的方式進行開發,進行查詢的時候再進行計算,這就比較依賴數據庫的能力了。
如果不涉及維度的更新,則是將 DWD 分成兩個視圖,一個映射到歷史分區,一個映射到當前的分區,DWD 表看起來就是一張表,下游可以直接做全量的計算,計算代碼保持統一,那麼計算結果也就保持了統一,統計之後再展示給前臺。
上述表述可以看出,一些複雜的統計場景,如長週期累計統計,或者是多維度分析場景,受制於基礎框架能力,不建議用實時方案來做。
本身在數倉場景中,ADS 就是需要靈活設計的一層,因此實時數倉根據業務的不同,也需要做出靈活的變化。
因此,目前看還不存在統一的數倉結構方案,仍需要基於我們的架構選型,進行靈活的設計。
|0xFF 常見問題的解決
實時數倉,相較於離線數倉,有一些場景是需要做特殊考量和設計的。
第一個場景,是維表更新問題。
對於離線數倉而言,維度信息可以冗餘到事實表中,因爲數據都是一次性算好、一次性使用,這麼做問題不大。但實時場景中,但維度信息發生變化後,如果依舊做冗餘到事實表的設計,那麼更新後的情況就無法被反應出來。因此,維度更新後,我們往往就需要用最新的維度數據,來刷新歷史數據,但如果維度變化很頻繁,那麼這麼做基本就是不可接受的。
基於如上的考慮,維度和事實,在實時數倉中,需要更嚴格的做區分,模型的設計更加傾向於範式建模,而非維度建模。如果數據庫性能更得上,通常可以選擇將維度數據和事實數據分開存儲,最後查詢的時候再做彙總。當然,維表更新,還需要考慮雙流 join 等問題,挑戰不可謂不大。
第二個場景,是數據質量的問題。
離線數據的質量保障,做的是比較好的,不僅有測試同學的輔助驗證,還有平臺提供的各種校驗工具。但因爲實時計算鏈路的特殊性,我們過去積累的經驗和工具,往往無法複用在實時場景下,導致目前的實時質量依舊只能是人肉爲主。
相對而言,離線的鏈路靠譜的多,我們就會考慮用離線的數據來修正實時的數據。而且,離線的數據還有完整的數據管理、數據權限、數據安全機制,這些都是實時數倉短時間內無法實現的、但非常有必要的功能。
第三個場景,是公共層建設的要求。
針對離線數倉,公共層有的時候設計很薄弱,是沒有問題的,因爲數據量總會要在某一層削減掉,這一層是在公共層還是應用層,問題都不是特別大。但實時數倉就需要考慮流量暴漲的情況,如果 ADS 直接訪問明細數據層,那麼響應延遲的增加就再所難免。
因此,實時數倉,對於業務場景的選擇,就顯得挑剔的多,公共層的本意是爲了屏蔽底層變化對上游應用產生的影響,而我們要做的,就是在性能、成本、效率、質量之間取得平衡。
最後,流批一體,最大的意義,其實是用一套代碼,實現兩種計算模式,並不是完全的純實時,這也是制約流批一體發展的最大問題。因此,未來發展方向,大概率會走向純實時開發的鏈路,同時補全諸如質量保證、數據安全等方面的內容,這都需要比離線數倉更長的發展時間。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/qbGfPcnRKNtn5Nf-HZcZ3w