【Spark】Spark容錯機制

farsun發表於2021-09-09

引入

一般來說,分散式資料集的容錯性有兩種方式:資料檢查點和記錄資料的更新
面向大規模資料分析,資料檢查點操作成本很高,需要透過資料中心的網路連線在機器之間複製龐大的資料集,而網路頻寬往往比記憶體頻寬低得多,同時還需要消耗更多的儲存資源。
因此,Spark選擇記錄更新的方式。但是,如果更新粒度太細太多,那麼記錄更新成本也不低。因此,RDD只支援粗粒度轉換,即只記錄單個塊上執行的單個操作,然後將建立RDD的一系列變換序列(每個RDD都包含了他是如何由其他RDD變換過來的以及如何重建某一塊資料的資訊。因此RDD的容錯機制又稱“血統(Lineage)”容錯)記錄下來,以便恢復丟失的分割槽。
Lineage本質上很類似於資料庫中的重做日誌(Redo Log),只不過這個重做日誌粒度很大,是對全域性資料做同樣的重做進而恢復資料。

Lineage機制

Lineage簡介

相比其他系統的細顆粒度的記憶體資料更新級別的備份或者LOG機制,RDD的Lineage記錄的是粗顆粒度的特定資料Transformation操作(如filter、map、join等)行為。當這個RDD的部分分割槽資料丟失時,它可以透過Lineage獲取足夠的資訊來重新運算和恢復丟失的資料分割槽。因為這種粗顆粒的資料模型,限制了Spark的運用場合,所以Spark並不適用於所有高效能要求的場景,但同時相比細顆粒度的資料模型,也帶來了效能的提升。

兩種依賴關係

RDD在Lineage依賴方面分為兩種:窄依賴(Narrow Dependencies)與寬依賴(Wide Dependencies,原始碼中稱為Shuffle
Dependencies),用來解決資料容錯的高效性。

  • 窄依賴是指父RDD的每一個分割槽最多被一個子RDD的分割槽所用,表現為一個父RDD的分割槽對應於一個子RDD的分割槽
    或多個父RDD的分割槽對應於一個子RDD的分割槽,也就是說一個父RDD的一個分割槽不可能對應一個子RDD的多個分割槽。
    1個父RDD分割槽對應1個子RDD分割槽,這其中又分兩種情況:1個子RDD分割槽對應1個父RDD分割槽(如map、filter等運算元),1個子RDD分割槽對應N個父RDD分割槽(如co-paritioned(協同劃分)過的Join)。

  • 寬依賴是指子RDD的分割槽依賴於父RDD的多個分割槽或所有分割槽,即存在一個父RDD的一個分割槽對應一個子RDD的多個分割槽。
    1個父RDD分割槽對應多個子RDD分割槽,這其中又分兩種情況:1個父RDD對應所有子RDD分割槽(未經協同劃分的Join)或者1個父RDD對應非全部的多個RDD分割槽(如groupByKey)。


    圖片描述

本質理解:根據父RDD分割槽是對應1個還是多個子RDD分割槽來區分窄依賴(父分割槽對應一個子分割槽)和寬依賴(父分割槽對應多個子分
區)。如果對應多個,則當容錯重算分割槽時,因為父分割槽資料只有一部分是需要重運算元分割槽的,其餘資料重算就造成了冗餘計算。

對於寬依賴,Stage計算的輸入和輸出在不同的節點上,對於輸入節點完好,而輸出節點當機的情況,透過重新計算恢復資料這種情況下,這種方法容錯是有效的,否則無效,因為無法重試,需要向上追溯其祖先看是否可以重試(這就是lineage,血統的意思),窄依賴對於資料的重算開銷要遠小於寬依賴的資料重算開銷。

窄依賴和寬依賴的概念主要用在兩個地方:一個是容錯中相當於Redo日誌的功能;另一個是在排程中構建DAG作為不同Stage的劃分點。

依賴關係的特性

第一,窄依賴可以在某個計算節點上直接透過計算父RDD的某塊資料計算得到子RDD對應的某塊資料;寬依賴則要等到父RDD所有資料都計算完成之後,並且父RDD的計算結果進行hash並傳到對應節點上之後才能計運算元RDD。
第二,資料丟失時,對於窄依賴只需要重新計算丟失的那一塊資料來恢復;對於寬依賴則要將祖先RDD中的所有資料塊全部重新計算來恢復。所以在長“血統”鏈特別是有寬依賴的時候,需要在適當的時機設定資料檢查點。也是這兩個特性要求對於不同依賴關係要採取不同的任務排程機制和容錯恢復機制。

容錯原理

在容錯機制中,如果一個節點當機了,而且運算窄依賴,則只要把丟失的父RDD分割槽重算即可,不依賴於其他節點。而寬依賴需要父RDD的所有分割槽都存在,重算就很昂貴了。可以這樣理解開銷的經濟與否:在窄依賴中,在子RDD的分割槽丟失、重算父RDD分割槽時,父RDD相應分割槽的所有資料都是子RDD分割槽的資料,並不存在冗餘計算。在寬依賴情況下,丟失一個子RDD分割槽重算的每個父RDD的每個分割槽的所有資料並不是都給丟失的子RDD分割槽用的,會有一部分資料相當於對應的是未丟失的子RDD分割槽中需要的資料,這樣就會產生冗餘計算開銷,這也是寬依賴開銷更大的原因。因此如果使用Checkpoint運算元來做檢查點,不僅要考慮Lineage是否足夠長,也要考慮是否有寬依賴,對寬依賴加Checkpoint是最物有所值的。

Checkpoint機制

透過上述分析可以看出在以下兩種情況下,RDD需要加檢查點。

  1. DAG中的Lineage過長,如果重算,則開銷太大(如在PageRank中)。

  1. 在寬依賴上做Checkpoint獲得的收益更大。

由於RDD是隻讀的,所以Spark的RDD計算中一致性不是主要關心的內容,記憶體相對容易管理,這也是設計者很有遠見的地方,這樣減少了框架的複雜性,提升了效能和可擴充套件性,為以後上層框架的豐富奠定了強有力的基礎。
在RDD計算中,透過檢查點機制進行容錯,傳統做檢查點有兩種方式:透過冗餘資料和日誌記錄更新操作。在RDD中的doCheckPoint方法相當於透過冗餘資料來快取資料,而之前介紹的血統就是透過相當粗粒度的記錄更新操作來實現容錯的。

檢查點(本質是透過將RDD寫入Disk做檢查點)是為了透過lineage做容錯的輔助,lineage過長會造成容錯成本過高,這樣就不如在中間階段做檢查點容錯,如果之後有節點出現問題而丟失分割槽,從做檢查點的RDD開始重做Lineage,就會減少開銷。

轉載請註明作者Jason Ding及其出處



作者:JasonDing
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4289/viewspace-2818612/,如需轉載,請註明出處,否則將追究法律責任。

相關文章