在開始說如何建設實時數倉之前,我們先說一下建設實時數倉的目的,實時數倉解決了什么問題。
其實在很多情況下,我們對於實時數倉的定位可能是沒有那么准確的。我們都知道,傳統數倉一個非常重要的功能是用於記錄歷史,而實時數倉恰恰相反,它更重視處理當前的狀態。
因此,我們創建實時數倉的目的就在於解決傳統數據倉庫由於時效性低而解決不了的問題。傳統數倉可以解決的問題,我們不解決;如果問題本身就不適合用數倉解決的話,我們也不去解決。這是我們建設實時數倉的一些基本原則。
實時數倉作為數倉的一種,他也包含面向主題、有集成性、相對穩定等的數據倉庫本身的特性。不過於傳統數倉不同的是,它只保留上一次批處理到當前的數據(一般只保留3天)。這樣的話,我們就有兩天完整的數據,在批處理還沒來得及處理完昨天的數據的間隙中,數倉仍然可以提供較好的服務。
上面說了實時數倉不解決的問題,那么哪些問題是我們要解決的呢?
-
實時OLAP分析
-
實時數據看板
-
實時特性,用戶畫像的建立
-
實時業務監控,比如說核心業務指標的監控預警等等。
2 實時數倉的架構
在開始建設前,我們還需要了解他的架構,這就像造船的龍骨一樣,如果沒有好的架構,搭建起來的數倉也不會是一個好的數倉。
前面咱們說過,實時數倉用於解決傳統數倉解決不了的問題,那么我們有必要先了解一下傳統數倉的架構。
2.1 傳統數倉架構
從圖中可以看到,傳統的數據倉庫是基於hdfs進行建設的,它的架構主要分為三個部分,數據源、離線數據倉庫、數據應用。
數倉的數據來源分為兩部分,一部分是埋點行為日志,這部分數據來源於我們的web應用、APP等的前端埋點,記錄的是用戶的行為。另一部分是業務數據庫中的數據,一般是mysql等關系型數據庫中存儲的業務數據。
離線數據倉庫中一般分為ODS層、DWD層、DIM層、DWS層、應用數據層。當然不同的地方對每一層的叫法可能會有所不同。但是大概是這個樣子,它使用hive/spark/mr等計算引擎進行計算,支持天或者小時級的延遲處理。
ods層存儲的是原始數據,這里面的數據是最細粒度的,沒有任何變動的數據。dwd明細數據層存儲的是明細數據,及ods中的數據經過簡單的ETL之后的明細數據。同時還有dim維表,這里面存儲的是維度數據。dws匯總數據層中存儲的是匯總層的數據,這里的數據一般是按照主題,或者業務進行區分的寬表數據。最后就是APP應用數據層,這里面存儲的是最后提供給外部應用的結果數據。
數據應用是我們數據倉庫中的數據的使用位置,我們可以將倉庫中的數據存儲到hbase等的數據庫中作為數據服務為其他業務提供支持,也可以用作數據報表,數據產品等地方。
2.2 lamdba架構
而實時數倉於傳統數倉不同,剛開始實時數倉的架構叫做lambda架構,如下圖所示。
lamdba架構是一個比較經典的架構,在以前實時場景並不是很多,大部分的業務都已離線為主,再附加了實時場景之后,由於他們之間的時效性不同,導致其技術生態也不一樣。lambda架構相當於在離線數倉的基礎上附加了一條實時生產鏈路,在應用層面進行一次整合。雙鏈路生產,相互獨立。
不過這種架構也存在着一些問題,比如說加工邏輯、開發運維等都要進行double操作,成本高,開發維護麻煩。同時資源同樣也是兩個資源鏈路。
因此產生了kappa架構。
2.3 kappa架構
kappa架構移除了離線數倉的部分,全部采用實時生成。從架構設計來講,比較簡單,生產統一,一套邏輯同時生產離線和實時數據。
2.4 實時OLAP變體
在kappa架構上,我們可以將APP應用數據存儲到OLAP引擎中,由實時OLAP引擎承擔聚合分析運算,這樣可以減輕實時計算部分的計算壓力。這種可以成為kappa架構的一個變體。
2.5 小結
從以上幾種架構我們可以發現,實時數倉相對於傳統數倉來說,它的層級更少。這樣可以保證它有更少的延遲。
ODS層在kafka中存儲的是原始數據,這里業務數據庫我們可以使用canal監控mysql的binlog日志傳入kafka。DW層存儲匯總數據,經過flink計算后同樣存儲於kafka。DIM維度表可以存儲在redis、hbase、es等的熱存儲引擎中。至於APP應用數據層我們會直接寫入應用數據庫,也就是說實時數倉並不去維護APP應用數據。
我們也可以看一下這些架構之間的區別
lamdba | kappa | 實時OLAP變體 | |
---|---|---|---|
計算引擎 | 流批兩套計算引擎 | 流計算引擎 | 流計算引擎 |
開發成本 | 高,需要同時維護實時、離線兩套代碼 | 低,只需要維護一套代碼 | 低,只需要維護一套代碼 |
OLAP分析靈活性 | 中 | 中 | 高 |
是否依賴實時OLAP引擎 | 非強依賴 | 非強依賴 | 強依賴 |
計算資源 | 需要流批兩套計算資源 | 只需要流計算資源 | 需要流計算資源和實時OLAP資源 |
邏輯變更重算 | 通過批處理重算 | 重新消費消息隊列 | 重新消費消息隊列,重新導入OLAP引擎 |
3 實時計算的技術選型
在了解了架構之后我們還需要確定實時計算的技術選型。
目前,市面上已經開源的實時技術還是很多的,比較通用的有Storm、Spark Streaming以及Flink。
在幾年前,業界使用的一般是Storm。當時的Storm,在性能穩定性、可靠性以及擴展性上是無可替代的。但隨着Flink越來越成熟,從技術性能及框架設計又時尚已經超越了Storm,從趨勢來講就像Spark替代MR一樣,Flink也會慢慢替代Strom。
Flink和Storm的對比
Flink | Storm | |
---|---|---|
狀態管理 | 內部包含狀態管理 | 無狀態,需要用戶自行進行狀態管理 |
窗口支持 | 窗口支持比較完善,自帶一些窗口聚合方式,會自動管理窗口狀態 | 對事件窗口支持較弱,緩存整個窗口的所有數據,窗口結束時一起計算 |
消息投遞 | 最多一次 最少一次 精確一次 | 最多一次 最少一次 |
容錯方式 | 檢查點機制,通過分布式一致性快照機制,對數據流和算子狀態進行保存。發生錯誤是進行回滾。 | ACK機制,對每條消息進行全鏈路跟蹤,失敗或超時進行重發 |
性能 | 吞吐量是Storm的3倍更多,延時明顯低於Storm | 穩定,可靠 |
4 如何建設實時數倉
現在我們就可以着手於實時數倉的創建了。
從上面的架構中我們其實可以感覺到,實時數倉相對於傳統數倉而言,他的數據存儲更多,同時層級更少。
-
存儲更多
在離線數倉中,我們所有的表幾乎都是hive表,而在實時數倉中,我們會根據表的用途將他們存儲在不同的地方,比如說維度數據,我們可能存儲在Redis、ES等數據庫中。其他數據可能在HBase,kafka等地方。
-
層級更少
在以往建設數倉的時候,APP數據應用層是在倉庫內部的。而在實時數倉中,APP層並不算在倉庫中,而是放到了外部存儲中,以作他用。
同時在DW層我們也要保證由更少的層級,因為在計算的時候,我們為了得到更加准確的結果,可能人為設置一些延遲,來等待遲到數據。層級越多,延遲也就也高。
4.1 ODS層
當然在這里我們是講一些需要注意的點,主要有兩個方面。
-
數據來源盡量統一
這里統一的概念主要由兩個。
-
一個是實時數據源本身要與自己相統一。比如說咱們需要從Mysql中去讀取數據,我們盡可能用一種方式去讀取,像binlog,不要同時使用多種讀取方式。
-
實時和離線的統一。雖然咱們是在建設實時數倉,但是他也是屬於數倉。在倉庫中我們要保證數據來源的統一,不能讓使用的人產生誤解。
-
-
利用分區保證數據局部有序
我們在采集數據的時候,因為網絡延遲等原因可能會造成數據亂序,也就是先發生的數據后消費。針對這個問題我們可以通過kafka的分區來保證數據的局部有序。
4.2 DWD層
DW層它的建設其實和離線數倉中DW層的建設基本一致。主要是為了解決一些原始數據中存在的噪點、數據不完整和數據格式不一致的問題,形成規范、統一的數據源。
這里的話盡可能做到和離線數倉一樣的入倉方式(入什么倉,如何入倉)。比如說我們可以建設基於配置的入倉規則,實時和離線用同一套規則入倉。
DWD層主要的工作包括數據解析、業務整合、臟數據的清洗和模型規范化。
這里我們重點講一下模型規范化,實時數倉和離線數倉不同的是,實時數倉他是7*24小時不間斷運行的。如果需要更改表字段的話,會付出比離線更多的代價。因為要保證數據上游和下游的數據可以解析到新的表結構。還有就是我們存儲使用的是kafka,kafka不像其他的數據庫。它不能做結構化存儲,同時也沒有辦法管理元數據。因此,我們建議在開始構建數倉前就做好數據的模型規范化。避免后續付出更多的代價來做數據治理。
同時,我們還可以針對數據本身做一些處理,為了應對一些生產環境中的常見問題,我們可以在數據上額外補充一些信息。
-
唯一鍵和主鍵
在數倉中我們針對日志進行處理,比如說我們通過binlog來處理MYSQL中的數據,MYSQL中存儲的是一些業務數據,比如說訂單數據,每一行訂單數據可能會有多次改變,這些變化又通過一條條的binlog日志來體現。那這個時候我們就可以通過唯一鍵和主鍵來標記每條數據。其中唯一鍵用來標記唯一一條數據,這個可以解決數據重復的問題;主鍵用來標記唯一一行數據,這個可以利用kafka的分區來解決是數據亂序的問題。
-
版本號和批次
因為在數倉中,下游數據的處理邏輯是依賴於上游表的schame的,我們在計算過程中可能會遇到需要重新計算的問題或者說數據的表結構發生了變化的情況。這個時候我們就可以通過數據的版本和批次去分別解決。這里的版本號指的的是數據表結構的版本號,我們可以通過不同的版本號來判斷表結構變化的問題。而批次指的是數據重導時的批次變化,可以通過更改數據的批次來保證及時數據的消費位置發生變化后也可以得到正確的結果。
4.3 DIM層
DIM層的數據都是數倉中的維度數據,維度數據我們可以根據他的變化頻率分為兩大類,變化頻率低的和變化頻率高的。針對不同的數據我們有不同的處理方式。
對於變化頻率較低的維度數據,比如說地域信息等,我們可以通過離線中的維度數據同步到緩存或者通過一些公共服務或者維度服務進行查詢,然后將其緩存中進行訪問。
至於變化頻率較高的維度數據,比如說一些商品的價格等信息,我們這個時候就需要監聽其變化情況,去創建一張價格變動的拉鏈表。
當然,維度數據我們都是用作關聯操作,也就是join,可以用於一般的ETL場景。其方式也有很多種,因為我們一般使用Flink作為實時計算引擎,所以我這里寫一些Flink中常用的join操作方式。
-
維度join
在做維度join的時候,我們一般是將維度表全量預加載到內存中做關聯。它實現簡單,好操作。但是僅支持小數據量的維表,而且維表更新時必須重新啟動任務。它適用於小維表,同時變化頻率低,對變更及時性要求低的場景。
-
熱存儲關聯
實時流於熱存儲(redis、es等)中維度數據的關聯,同時使用cache減緩存儲訪問壓力。這種方式中維度數據數據不受限於內存,可以支持更多的唯獨數據,不過需要熱存儲資源,維度的更新反饋到結果也存在一定的延遲。適用於維度數據量較大,同時可以接受維度更新有一定的延遲的場景中。
-
廣播維表
利用broadcast state將維度數據流官博到下游task做join操作。這種情況下可以及時察覺到維度數據的更新。但是數據保存在內存,所以支持較少的數據量。適用於需要實時感知維度數據變更的場景。
4.4 DWS層
DWS層即匯總層。這一層的建設也是和離線數倉的建設方法一致。
這一層主要是對共性指標的統一加工,同時根據主題進行多維度的匯總等操作。可以使用Flink中豐富的時間窗口實現。
5 總結