目錄
一、概述
二、RDD的核心概念
2.1 Partition
2.2 Partitioner
2.3 RDD的依賴關系
2.4 Stage
2.5 PreferredLocation
2.6 CheckPoint
三、RDD的持久化
3.1 概述
3.2 概念
3.3 RDD持久化級別
3.3.1 MEMORY_ONLY
3.3.2 MEMORY_AND_DISK
3.3.3 MEMORY_ONLY_SER
3.3.4 OMEMORY_AND_DISK_SER
3.3.5 DISK_ONLY
3.3.6 MEMORY_ONLY2和MEMORY_AND_DISK2
3.3.7 OFF_HEAP
3.4 RDD 持久化原則
3.5 刪除RDD持久化緩存
一、概述
RDD是 Spark 中最基本的數據抽象,代表一個不可變、可分區、元素可并行計算的集合。RDD具有自動容錯、位置感知性調度和可伸縮等特點。RDD 允許用戶在執行多個查詢時顯式地將數據集緩存在內存中,后續查詢能夠重用該數據集,這極大地提升了查詢效率。
二、RDD的核心概念
2.1 Partition
RDD內部的數據集在邏輯上和物理上都被劃分為多個分區(Partition)以提高運行的效率,分區數量決定了計算的并行度,每一個分區內的數據都在一個單獨的任務中被執行,如果在計算過程中沒有指定分區數,那么 Spark 會采用默認分區數量。默認分區數量為程序運行分配到的CPU核數。
2.2 Partitioner
Partitioner 是 RDD的分區函數。分區函數不但決定了 RDD本身的分區數量,也決定了其父 RDD Shuffle 輸出時的分區數量。Spark 實現了基于 Hash(HashPartitioner)和基于范圍(RangePartitioner)的兩種分區函數。
注意:只有對于Key-Value的RDD才會有 Partitioner,而非 Key-Value的RDD的Parititioner 值是None。
2.3 RDD的依賴關系
RDD的每次轉換都會生成一個新的 RDD,因此RDD之間會有前后依賴關系。當在計算過程中出現異常情況導致部分分區數據丟失時,Spark 可以通過依賴關系從父 RDD 中重新計算丟失的分區數據,而不需要對 RDD上的所有分區全部重新計算。RDD的依賴分為窄依賴和寬依賴。
- ?窄依賴:如果父 RDD的每個分區最多只能被子RDD的一個分區使用,則稱之為窄依賴。
- 寬依賴:如果父 RDD的每個分區都可以被子RDD的多個分區使用,則稱之為寬依賴。
窄依賴的每個子RDD的Partition 的生成操作都是可以并行的,而寬依賴則需要所有父Partition Shuffle結果完成后再被執行。Spark的窄依賴和寬依賴如圖所示:
2.4 Stage
Stage 是由一組 RDD組成的可進行優化的執行計劃。如果 RDD的依賴關系為窄依賴,則可放在同一個 Stage 中運行;若 RDD的依賴關系為寬依賴,則要劃分到不同Stage 中。這樣,當Spark 執行作業時,會按照Stage 劃分不同的RDD,生成一個完整的最優的執行計劃,使每個 Stage 內的 RDD都盡可能在各個節點上并行地被執行,
如圖所示:
階段三 包含 階段一和 階段二,其中,階段一為寬依賴,階段二為窄依賴。
2.5 PreferredLocation
PreferredLocation 是一個用于存儲每個 Partition 的優先位置的列表。對于每個 HDFS文件來說,這個列表保存的是每個 Partition 所在的塊的位置也就是該HDFS文件的“劃分點”。
2.6 CheckPoint
CheckPoint 是Spark 提供的一種基于快照的緩存機制。當需要計算的 RDD 過多時,為了避免任務執行失敗后重新計算之前的 RDD,可以對 RDD 做快照(CheckPoint)處理,檢查 RDD 是否被計算,并將結果持久化到磁盤或 HDFS 上。
此外Spark 提供另一種緩存機制 Cache,Cache 緩存數據由 Executor 管理,當Executor 消失時Cache 緩存的數據將被清除,而 CheckPoint將數據保存到永久性磁盤或HDFS,當計算出現運行錯誤時,Job可以從CheckPoint 點繼續計算。
三、RDD的持久化
3.1 概述
Spark 可以跨節點在內存中持久化 RDD。當持久化 RDD時,每個節點都會在內存中緩存計算后的分區數據,當其他操作需要使用該 RDD 時,可以直接重用該緩存數據,這使得之后的 RDD 計算速度更快(通常超過10倍)。緩存是選代計算和交式計算的關鍵。
3.2 概念
應用程序可以使用 persist0或 cache0標記要緩存的 RDD,當調用操作(Action)執行計算時,計算結果將被緩存在節點的內存中。Spark 緩存具有容錯性,如果 RDD的某個分區丟失,則該RDD將被自動重新計算。
每個持久化 RDD 都可以使用不同存儲級別進行存儲,Spark 允許將數據集存儲在磁盤上或內存中。Spark 將需要緩存的數據序列化為 Java 對象(序列化可以節省磁盤或內存空間),然后跨節點復制到其他節點上,以便其他節點重用該數據。Spark 中緩存持久化級別是通過StorageLevel來設置的。具體代碼如下
lineLengths.persist(storageLevel.MEMORY_ONLY());
3.3 RDD持久化級別
3.3.1 MEMORY_ONLY
使用未經過序列化的 Java 對象在內存中存儲 RDD。當內存不夠時,將不會進行持久化:當下次需要該 RDD 時,再從源頭處重新計算。該策略是默認的持久化策略,當使用 cache()時,使用的是該持久化策略。
3.3.2 MEMORY_AND_DISK
使用未經過序列化的 Java 對象存儲 RDD,優先嘗試將RDD保存在內存中。如果內存不夠,則會將 RDD寫人磁盤文件;當下次需要該 RDD時從持久化的磁盤文件中讀取該 RDD 即可。
3.3.3 MEMORY_ONLY_SER
MEMORY_ONLY_SER 的含義與 MEMORY_ONLY 類似唯一區別是MEMORY_ONLY_SER 會將 RDD中的數據進行序列化。在序列化過程中,RDD的每個 Partition 都將會被序列化成一個字節數組,這種方式更加節省內存,從而避免持久化的RDD占用過多內存導致JVM頻繁GC。
3.3.4 OMEMORY_AND_DISK_SER
MEMORY_AND_DISK_SER 的含義與 MEMORY_AND_DISK類似。唯一區別是MEMORY_AND_DISK_SER會將RDD中的數據進行序列化。在序列化過程中,RDD的每個 Partition 都會被序列化成一個字節數組。這種方式更
加節省內存,從而避免持久化的 RDD占用過多內存導致頻繁GC。
3.3.5 DISK_ONLY
使用未序列化的Java對象將 RDD全部寫人磁盤文件。
3.3.6 MEMORY_ONLY2和MEMORY_AND_DISK2
對于上述任意一種持久化策略如果加上后綴 2,代表的是將每個持久化的數據都復制一份副本,并將副本保存到其他節點上。這種基于副本的持久化機制主要用于容錯。假如某個節點掛掉,節點的內存或磁盤中的持久化數據丟失了,那么后續對 RDD 計算時還可以使用該數據在其他節點上的副本。如果沒有副本,則只能將這些數據從頭重新計算一遍。
3.3.7 OFF_HEAP
OFF_HEAP與MEMORY_ONLY_SER類似,OFF_HEAP將數據存儲在堆外內存中。該參數需要Spark 啟用堆外內存。
3.4 RDD 持久化原則
Spark 提供了豐富的存儲級別,旨在通過不同存儲級別的設置實現內存和CPU的最佳使用,具體開發中該如何選擇持久化方案呢?以下為 Spark 官方提供的緩存持久化的選擇流程。
- 如果RDD在默認存儲級別(MEMORYONLY)下運行良好,則建議使用MEMORY_ONLY。該級別是CPU效率最高的類型,基于CPU快速計算可以使 RDD上的操作盡可能快地運行。
- 如果系統顯示內存使用過高,則嘗試使用MEMORY_ONLY_SER,并選擇更快速的序列化庫,以加快序列化時間和節省對象的存儲空間。
- 如果要快速恢復故障,則建議使用副本存儲級別。其他存儲級別需要通過重新計算丟失的數據來保障緩存的完整性,而副本存儲級別可以在其緩存對應的副本節點上直接執行任務,不用等待重新計算丟失的分區數據
3.5 刪除RDD持久化緩存
Spark 會自動監視每個節點上的緩存使用情況,并以 LRU方式刪除舊的數據分區如果想手動刪除RDD,則可通過RDD.unpersist()方法完成。
今天Spark RDD的相關內容就分享到這里,可以關注Spark專欄《Spark》,后續不定期分享相關技術文章。如果幫助到大家,歡迎大家點贊+關注+收藏,有疑問也歡迎大家評論留言!