內容來源:2018 年 5 月 5 日,小米HBase研發工程師吳國泉在“ACMUG & CRUG 2018 成都站”進行《大資料時代系統體系架構和對比:儲存與計算》演講分享。IT 大咖說(微信id:itdakashuo)作為獨家視訊合作方,經主辦方和講者審閱授權釋出。
閱讀字數:2972 | 8分鐘閱讀
獲取嘉賓演講視訊及PPT:
摘要
大資料時代,各種分散式框架層出不窮,儲存方面有: HDFS, ES, HBase... 計算方面有:MR, Spark, Flink等等。如何根據業務選取合適的技術方案,相信一定是大家都比較關心的問題,這次的分享就簡單談一談我對現在比較主流的分散式框架的理解,希望能和大家一起學習進步。
MySQL、HBase、Elastcisearch的特點和區別
MySQL、HBase、Elastcisearch是目前比較流行的儲存方式。Mysql廣泛應用於OLTP業務,支援事務,提供二級索引。HBase面向海量資料儲存,有良好的寫效能,讀效能稍差,不支援事務和二級索引。ES適用於複雜查詢和全文檢索,不支援事務。接下來我們將通過儲存方式和讀寫方式這兩個方面來分析他們的特點。
儲存方式
常見的儲存方式有行存和列存兩種。行存的形式如上圖,一條一條記錄連續存放,這種方式比較適合於線上,比如一次性讀取檢索到的資料的全部資訊。列儲存適合於一些資料分析的業務,這種情況下不需要全部資訊,只需特定欄位下的相關資料。
與前兩種方式不同,ES儲存的是倒排索引,適用於全文檢索的業務。如圖所示原始文件的內容在儲存的時候首先會進行分詞,然後這些分詞會被組合成字典,每個字典後有對應的連結串列,連結串列儲存的就是該分詞所在的文件ID。這樣就可以通過一些關鍵字快速的定位到文件資訊。
讀寫方式
Mysql的讀寫方式是典型的1+4,其特點在於所有的讀寫都有可能是隨機IO。而HBase的每張表都是由很多Region組成,寫模式下資料首先會被寫入記憶體,當記憶體到達某個閾值之後會進行刷盤生成一個小檔案,任何的更新、插入、刪除操作都被當做寫操作,都是順序寫記憶體然後刷到盤中。讀的時候是通過元件定位到指定Region,然後遍歷Region上的所有小檔案。這相當於犧牲了讀效能來提高寫效能。ES的寫入類似於HBase,同樣是先寫記憶體然後刷盤,不過效能上不如HBase,因為ES在建立倒排索引的時候不僅要做分組,還有評分、壓縮之類的操作。雖然ES寫入效能較差,但正因為在寫入的時候做了這些複雜的計算,所以獲得了很強的檢索功能。
上圖對MySQL、HBase、ES之間的特點進行了詳細的總結。關於一致性的問題,這裡需要提一下。ES寫入資料的時候會建立索引,這個操作會耗費一定的時間,因此ES中資料從寫入到可以檢索到預設的時間間隔為1s。
計算
解決了資料儲存問題之後,接下來就是發現資料價值,這就要利用到計算框架。對此我們主要探討兩方面,離線計算和實時計算。
離線計算
移動計算優於移動資料是MapReduce的早期思想,因此當Map任務在HDFS節點啟動的時候,資料不用遷移就可以直接在資料中跑計算任務,當然Reduce階段還是要做彙總。需要注意的是即使記憶體足夠,Map階段的資料也還是會落盤。
對於上圖中的 ,相信大家一眼就能求出解。而計算機求解的時候首先會將該方程轉換成下面的形式,然後假設一個初始值代入方程右邊獲得新的x值,接著進行不斷的迭代,當上一個x值和當前值的差值小於規定閾值的時候迭代結束。在AI和資料分析領域其實都會涉及到這樣的解方程形式以及迭代計算。如果用MapReduce來實現的話,每一次迭代都會啟動一個MapReduce任務,相對來說代價還是很大的。
針對以上兩點問題,Spark提供了一種新的RDD資料結構,如果資料可以存放在記憶體中就不會進行落盤。另外它還提供了更好的API,不僅是任務排程,在程式編寫方面也更加友好。
實時計算
在講實時計算之前需要明確一點,離線計算不等於批量計算,實時計算也不等於流式計算。離線和實時指的是資料處理的延時,批量和流式則是資料處理的方式。其實流式計算是可以完成批量計算的工作的,之所以還有批量計算框架,是因為流式計算的設計難度遠高於批量計算。google的流式計算負責人有過這樣的觀點——一個設計良好的流式系統可以完全取代批量系統。
目前實時計算有這樣幾個難點,分別是吞吐、exactly once、資料亂序。下面會分別介紹Storm、Spark、Flink針對這三點提出的解決方案。
Storm
上圖是Storm統計詞群的過程,首先由spout從輸入源中讀取一條資料,然後上游bolt接收資料進行分詞,接著下游bolt根據key值接收資料並將資料入庫,最終得到統計結果。
如果中間的分詞系統掛了,storm會提供一個acker任務,每個bolt在計算完之後都會向acker傳送一個ack資訊用來宣告任務執行成功,當整個流程中所有的ack資訊都傳送給acker之後,acker就認為這條資訊處理成功並返回成功訊息給輸入源。這種場景下ack資訊會隨著資料量增長,因此特別影響storm的效能,這也是早期我們認為流式計算的吞吐量不如批量計算的一個重要原因。
如果在處理的過程中某個計算節點掛了,而另外的節點卻入庫成功,這時acker會認為該條記錄已處理失敗進而重發,導致DB中的部分資料會重複累加。
Spark streaming
Spark streaming針對以上兩個問題進行了優化。首先是關於吞吐,不再是一條一條處理而是小批量的處理,預設間隔為1秒,這1秒內所接收到的資料會被生成為一個batch然後向下遊傳送,也就是通過擴大粒度來提高吞吐。
我們都知道離線計算本來就是精準計算架構,Spark streaming內部是利用spark的邏輯來保證exactly once。
Flink
Flink不再是一條一條資料做ack,而是在每段資料之間打上checkpoint,然後針對每段資料進行確認,如果任務掛掉就會在上一次成功的checkpoint點重新恢復資料。通過這種方式將流式計算和容災較好的結合起來。
流式計算會有一個視窗的概念,比如上圖中就有3個5秒視窗,方框中的編號代表事件發生的時間。可以看到第3秒的時候有兩條訪問事件,由於網路的延遲問題很有可能這3秒的資料會被分到第二個5秒視窗中,導致資料不正確。造成這樣結果的原因是早期的流式框架在處理資料的時候,將接收資料的時間認為是資料產生的時間。這裡延伸出裡了兩個概念,event time——資料真正產生的時間,process time——系統處理該資料的時間。對此最直觀的解決方案就是讓資料攜帶自身產生時的時間戳,流式系統以該時間戳為基準。