首頁>技術>

|0x00 從實時數倉的歷史談起

實時數倉的歷史,有三個顯著的分水嶺。

第一個分水嶺是從無到有,隨著以Storm為代表的實時計算框架出現,大資料從此擺脫了MapReduce單一的計算方式,有了當天算當天資料的能力。

第二個分水嶺是是從有到全,以Lambad和Kappa為代表的架構,能夠將實時與離線架構結合在一起,一套產品可以實現多種資料更新策略。

第三個分水嶺是從全到簡,以Flink為代表的支援視窗計算的流式框架出現,使離線和實時的邏輯能夠統一起來,一套程式碼實現兩種更新策略,避免了因為開發方式不統一導致的資料不一致問題。

未來會有第四個分水嶺,就是從架構走向工具,以Hologres為代表的HSAP引擎,用服務分析一體化的設計理念,極有可能徹底統一掉分析型資料庫和業務資料庫,再配合Flink,真正實現數倉的徹底實時化。未來不再存在離線和實時的區分,Flink + Hologres,用一套結構、一套產品,就完事了。

過去,面對實時,數倉的邏輯是:效能不夠,架構來補;現在,面對實時,數倉的邏輯是:既要、還要、全都要。

過去,我們使用OLAP引擎,是為了更快的查詢資料;現在,我們使用OLAP引擎,是為了當線上業務庫,替代Mysql用。

當我們覺得摩爾定律要失效時,它卻仍然在發展。當我們覺得數倉架構定型時,它卻依然在高速演化。只有瞭解歷史,才能看清未來,我想重新瞭解一下Lambda/Kappa/Flink的歷史,熟悉架構的演進,以此來探討實時數倉建設的一些問題。

我們先從Lambda的歷史講起。

|0x01 Lambda

對低成本規模化的資料服務,以及儘可能低延遲的資料應用,是推動Lambda架構誕生的原動力。

早期的Storm框架,能夠幫助解決低延遲的問題,但這個框架並不完美,其中一個痛點,便是Storm無法支援基於時間視窗的邏輯處理,這導致實時流無法計算跨週期的邏輯,使用者不得不尋找一些額外的方法來實現。為了解決痛點,Storm的作者Nathan Marz,提出了一種混合計算的方式,透過批次MapReduce提供離線結果,同時透過Storm提供最新的資料,這種離線與實時混合的框架,就是如今廣為流傳的“Lambda架構”。

亞馬遜上有一本《Big Data: Principles and best practices of scalable realtime data systems》,就是Nathan Marz用來詳細闡述Lambda架構的,而最重要的圖,就是下面這張:

Lambda架構透過兩條分支來整合實時計算和離線計算, 一條叫Speed Layer,用於提供實時資料, 另一條叫作Batch Layer & Serving Layer,用於處理離線的資料。

為什麼這麼設計呢?在深入理解Lambda之前,我們首先了解一下資料系統的本質,主要有兩個:一個是資料,另一個是查詢。

資料的本質,主要體現在三個方面:

when:資料的時間特性,對於分散式系統而言,這個特別重要,因為時間決定了資料發生的先後順序,也決定了資料計算的先後順序;what:資料的內容特性,資料本身是不可變的,分散式系統對資料的操作,可以簡化為兩點:讀取和新增,也就是Create和Read,而Update和Delete可以用Create來替代;where:資料的儲存特性,基於分散式系統資料不可變的特性,儲存資料只需要進行新增即可,系統的邏輯設計會更加簡單,容錯性也可以大幅度提升。

查詢的本質,特指一個公式:Query = Function(All Data)。

表面的意思是,不論資料是存在Mysql這種RDBMS的,還是MPP型別的,或者是OLAP、OLTP,甚至是檔案系統,都能夠支援查詢。

更深入一點,意味著資料的查詢,要支援Monoid特性,例如整數的加法就要支援:(a+b)+c=a+(b+c)。

概念本身比較抽象,這裡只需要瞭解,如果函式滿足Monoid特性,那麼計算時就可以支援分散到多臺計算機,進行平行計算。

瞭解了資料系統的本質,我們再看實時架構,我們就發現,如何在平衡效能和資源消耗的基礎上,滿足Query = Function(All Data)的特性,就是Lambda架構設計的精髓。

離線資料能夠支援龐大資料量的計算,耗時長,但處理的資料量大,適合歷史資料的處理。並且,因為我們不能避免系統或者人為發生的錯誤,那麼離線方案對於結果的兜底,要遠優於實時方案,任何問題都可以透過邏輯的修正,來得到最終正確的結果。所以查詢應該是:batch view=function(all data)

而實時資料要支援實時的部分,為了實現低延遲的特性,勢必要減少計算的資料量,那麼只針對增量的做處理,作為對離線處理的補充,就是一種最優的方案。這裡查詢就變成了:realtime view=function(realtime view,new data)

而最終的結果,因為要支援歷史+實時資料的查詢,所以需要合併前面的兩個結果集。如果我們的查詢函式滿足Monoid性質的話,只需要簡單合併兩個流的資料,就能得到最終的結果。所以:query=function(batch view, realtime view)

總結下來,Lambda架構就是如下的三個等式:batch view = function(all data)realtime view = function(realtime view, new data)query = function(batch view, realtime view)

這麼設計的優點,Nathan Marz也進行了總結,最重要的有三條,即:

高容錯:對於分散式系統而言,機器宕機是很普遍的情況,因此架構的設計需要是非常健壯的,即便是機器跪了,任務也要能正常執行。除此之外,由於人的操作也很容易出現問題,因此係統的複雜性要控制在一定的程度內。複雜度越高,出錯機率越大。低延遲:實時計算對於延遲的要求很高,對應的系統讀操作和寫操作應該是低延遲的,對系統資料的查詢響應也應該是低延遲的。可擴充套件:系統不僅要能夠適應多種業務形態,比如電商、金融等場景,當資料量或負載突然增加時,系統也應該透過增加更多的機器來維持架構效能。因此,可擴充套件性,應該是scale out(增加機器的個數),而不是scale up(增強機器的效能)。

最後,Lambda的架構,就設計成了我們經常看到的樣子:

儘管結果看起來是“正確的廢話”,但思考的過程,卻是非常的透徹和深入。這本書很不錯,但瞭解的人不多,感興趣的可以瞭解一下。

|0x02 Kappa

Lambad框架儘管考慮的很深入了,但仍然存在兩個問題:

第一個是資料複雜度高,由於有多套資料來源,因此口徑對齊就成為了一個大問題;同時,產品在建設時,互動上要考慮實時和離線兩套邏輯,面對邏輯多一點的業務,計算也會變得非常複雜;第二個是搭建成本高:不僅框架需要維護多套,開發人員需要熟悉多種框架,而且相互之間運維成本很高。

離線和實時維護兩套邏輯,太容易導致資料結果不一致,這個點非常痛!LinkedIn的Jay Kreps對此很不滿意,於是提出了“Kappa架構”,作為Lambda方案的簡化版,刪除了批處理系統的邏輯,認為資料只需要流式處理就可以。

這個方案的設計其實有一些暴力,讓我們看下主體思路是怎樣的:

以Kafka作為資料的儲存系統;當需要計算增量資料時,只需要訂閱相應的broker,讀取增量即可;當需要計算全量資料時,啟動一個流式計算的例項,從頭進行計算;當新的例項完成後,停止舊的例項,並刪除舊的結果。

架構上應該是這樣樣子:

邏輯上是這個樣子:

有一句話很適合Kappa架構,即“如無必要,勿增實體”,也就是隻有在有必要的時候才會對歷史資料進行重複計算。由於實時計算跟離線計算是同一套程式碼,因此規避了兩套邏輯帶來的結果不一致問題。但相應的,Kappa的效能其實就成為了一個問題,需要對例項的數量進行控制。

感興趣的,在這裡進行擴充套件閱讀:http://milinda.pathirage.org/kappa-architecture.com/

|0x03 Flink

我們經常聽說 "天下武功,唯快不破",大概意思是說 "任何一種武功的招數都是有拆招的,唯有速度快,快到對手根本來不及反應,你就將對手KO了,對手沒有機會拆招,所以唯快不破"。Apache Flink是Native Streaming(純流式)計算引擎,在實時計算場景最關心的就是"快",也就是 "低延時"。

Flink最近實在太火了,明面上,它有這些優點:

豐富的流式處理用例:事件驅動型應用程式;支援流式/批次處理;支援資料通道及ETL。正確性有保障:嚴格執行一次機制;基於事件時間的處理;複雜情況下的延遲資料處理。分層API機制:流式計算SQL與批次處理資料共存;資料流API與資料集API共存;基於時間和狀態的過程控制。

但實際上,Flink透過視窗和時間兩個大的特性,有效解決了資料的亂序、週期計算問題,再配合SQL層統一邏輯,解決了一套程式碼,同時支援實時和離線兩種模式。過去透過架構來解決效能不夠的問題,一下子變得不再重要了。

Spark是以批處理的技術為根本,並嘗試在批處理之上支援流計算;Flink則認為流計算技術是最基本的,在流計算的基礎之上支援批處理。

因為這種設計理念的差異,二者存在一些比較顯著的差異。例如在低延遲場景中,由於Spark是基於批處理的方式進行流式計算,因而在執行的過程中存在一些額外的開銷,如果遇到對延遲的要求非常苛刻的場景,例如百毫秒甚至十毫秒級別,Flink就存在顯著的優勢。

這裡也推薦一個大神的部落格:https://enjoyment.cool/catalog/

|0xFF 實時數倉的設計

講完了實時架構,我們再看實時數倉。

我們已經對離線數倉怎麼做很清楚了,但實時數倉要怎麼做,則沒有很明確的方法論。有一些觀點是,實時不需要數倉,也有一些觀點是,實時像離線一樣做數倉就行了。這其實都是不對的。

新中國在造核潛艇時,原本以為核潛艇 = 潛艇 + 核動力,不就是潛艇換一下動力源嘛,有什麼不同的,但實際做的時候才發現,核潛艇與潛艇,完全是兩個物種。今天很多人在看轟-6K的時候,樣子與轟6差不多,那它們應該是同一種飛機,但6K和6之間,除了殼子一樣,裡面的東西,已經完全沒什麼相似的了。

同樣,實時數倉與離線數倉,看起來是類似的,但實質卻是不同的。

例如,這裡提一個問題,實時數倉需要維度建模嗎?也可以說是的,也可以說不需要,這主要取決於業務的複雜度。其實離線數倉,在業務不復雜的情況下,也不需要,直接加工目標資料庫就行。如果離線都沒必要,那麼實時更沒必要。但如果業務搞的非常複雜,那麼不僅離線需要,實時也就需要。

但,離線與實時,數倉的挑戰和思路,還是有一些不同的。

實時數倉的挑戰,主要體現在四個方面:

時效性挑戰:實時數倉如果延遲大了,那麼跟分鐘級計算就沒有本質區別,因此如何儘可能的快,就是實時數倉最大的挑戰;準確性挑戰:離線資料有完整的質量保證體系,但這些在實時數倉還都是比較新的挑戰,過去我們透過流批一體解決了多資料來源帶來的結果不一致性,但如果保證開發結果的準確,挑戰依舊很大;穩定性挑戰:實時數倉與離線不同,資料計算過程中出現了錯誤,修補的成本非常高,甚至可能導致永久性的資料丟失;靈活性挑戰:離線數倉最大的特點,就是可以應對海量需求的開發挑戰,而實時數倉一旦執行任務太多,不論對開發還是運維,挑戰都是很大的,尤其是面對需求頻繁變更的場景。

從數倉的規範上看,各層的變化如下:

ODS:由於流批一體統一了資料來源,而且ODS原本就不對原始資料做處理,因此可以無需再建表,直接用資料來源即可;DWD:與離線類似,實時業務也需要構建事實明細表,但區別在於,離線方案中,我們為了提高明細表的使用便捷程度,往往會把一些常用的維度退化到事實表,但實時方案出於時效性的考慮,傾向於不退化或者只退化不會變的維度;DWS:這一層根據業務情況的不同,在實時數倉的建設策略上,差異比較大;通常情況下,離線建設DWS,是針對比較成熟的業務,將維度逐級上卷;這樣做能夠將邏輯進行收口,提高下游使用的複用率,但缺點就是做的比較厚重;如果實時業務不是那麼複雜,那麼就不建議將DWS建的很重;究其原因,彙總層的目的在於預計算、提升效率和保證指標的一致性,實時鏈路太長,容易造成高的延遲和比較大的資源消耗;DIM:維表在實時計算中非常重要,也是重點維護的部分,維表需要實時更新,且下游基於最新的維表進行計算;ADS:功能和用途不變。

除了維度建模,現在依然面臨幾個問題。

第一個是實時數倉是否能完全替代離線數倉。

答案是不能完全替代。尤其是對結果準確性要求非常高的場景,離線可以透過資料回刷等措施來對結果進行兜底,但實時一旦資料來源出錯,就很難再進行彌補了。

第二個是公共層是否有必要建設。

答案是有必要。如果面對流量暴漲的業務場景,如果實時沒有公共層縮減計算資料量的話,一些資料傾斜場景很有可能直接幹爆了整個實時體系。

第三個是資源的錯峰使用。

實時數倉的方案通常比較貴,為了解決成本壓力,通常會與離線方案進行混布。凌晨實時壓力小、離線壓力大,而白天實時壓力大、離線壓力小,這時就可以充分根據叢集資源執行情況,將水位線抹平。

後話:

其實本文涉及了兩個崗位的內容:資料開發和資料倉庫,從分工來看,資料開發更偏向底層,側重於工具的最佳化;資料倉庫更偏向業務,側重業務的最優實現。現代資料體系,單一崗位很難把所有的事情都做了(開發、數倉、分析、演算法),但又需要你懂所有崗位在做什麼。雖然我們都有共同的目標:資料科學家,但複合型人才,尤其是一專多能的人才,是邁向資料科學家過程中,檢驗階段性結果的一步。

本文只是簡單描述了一下實時數倉用到的一些原理性知識,以及部分的實踐知識,要想出真知,還是需要自己去實踐。大公司之所以是普通人嚮往的目標,正是因為大公司提供了最好的實踐機會,並不是做的有多好,只是練的足夠多。

13
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Java8 Optional解決空指標