[scala-spark]8. RDD的实现和编程接口
1. RDD的實現
- 作業調度
當對RDD執行“轉換操作”時,調度器(DGAScheduler)會根據RDD的血統來構建由若干調度階段(State)組成的有向無環圖(DAG),每個調度階段包含盡可能多的連續“窄依賴”轉換。調度器按照有向無環圖順序進行計算,并最終得到目標RDD。
調度器(TaskScheduler)向各節點分配任務采用延時調度機制并根據數據存儲位置來確定(數據本地性:移動計算而非移動數據)。若一個任務需要處理的某個分區剛好存儲在某個節點的內存中,則該任務會分配給該節點;如果在內存中不包含該分區,調度器會找到包含該RDD的最佳位置,并把任務分配給所在節點。
- 內存管理
Spark從大的方向上提供了兩種持久化RDD的存儲策略:一是存在內存中;二是存儲在磁盤中。
對于內存使用LRU回收算法來進行管理,當計算得到一個新的RDD分區,但沒有足夠空間來存儲時,系統會從最近最少使用的RDD中回收其一個分區的空間。除非該RDD是新分區對應的RDD,這種情況下Spark會將舊的分區繼續保留在內存中,防止同一個RDD的分區被循環調入和調出。這點很關鍵,因為大部分的操作會在一個RDD的所有分區上進行,那么很有可能已經存在內存中的分區將再次被使用。
- 檢查點支持
雖然血統可以用于錯誤后RDD的恢復,但是對于很長的血統的RDD來說,這樣的恢復耗時比較長,因此需要通過檢查點操作保存到外部存儲中。
Spark提供為RDD設置檢查點操作的API,可以讓用戶自行決定需要為哪些數據設置檢查點操作。另外由于RDD的只讀特性,使得不需要關心數據一致性問題。
2. RDD編程接口
Spark中提供了通用接口來抽象每個RDD,這些接口包括:
- RDD分區-partitions
一個RDD劃分成很多的分區(partition)分布在集群的節點中,分區的多少涉及對這個RDD進行并行計算的粒度。在RDD操作中用戶可以使用partitions方法獲取RDD劃分的分區數,當然用戶也可以設定分區數目。如果沒有指定將使用默認值,而默認數值是該程序所分配到CPU核數,如果是從HDFS文件創建,默認為文件的block數(有一點我們必須要注意,當我們顯示的設置分區數時,分區數不允許小于HDFS文件的block數)。
/ 使用textFile方法獲取指定路徑的文件,未設置分區數 val rdd = sc.textFile("/app/spark/workcount.txt") // 使用partitions方法獲取分區數,假設默認的分區數為2,那么將返回2 val partitionSize = rdd.partitions.size// 顯示地設置RDD為6個分區 rdd = sc.textFile("/app/spark/wordcount.txt", 6) // 獲取分區數,此時返回6 partitionSize = rdd.partitions.size- RDD首選位置(preferred locations)
在Spark形成任務有向無環圖(DAG)時,會盡可能地把計算分配到靠近數據的位置,減少數據網絡傳輸。當RDD產生的時候存在首選位置,如HadoopRDD分區的首選位置就是HDFS塊所在的節點。當RDD分區被緩存,則計算應該發送到緩存分區所在的節點進行,再不然回溯RDD的血統,一直找到具有首選位置屬性的父RDD,并據此決定子RDD的位置。?
- RDD依賴關系
在RDD中將依賴關系分成了兩種類型:窄依賴(Narrow Dependencies)和寬依賴(Wide Dependencies)。其中窄依賴是指每個父RDD的分區都至多被一個子RDD的分區使用,而寬依賴是多個子RDD的分區依賴一個父RDD分區。 這兩種依賴的區別從兩個方面來說比較有用。第一:窄依賴允許在單個集群節點上流水線式執行,這個節點可以計算所有父級分區。相反,寬依賴需要所有的父RDD數據可用,并且數據已經通過Shuffle完成。第二:在窄依賴中,節點的恢復更加高效,因為只有丟失的父級分區需要重新計算,并且這些丟失的父級分區可以并行地在不同節點上重新計算。相反,在寬依賴的繼承關系中,單個失敗的節點可能導致一個RDD的所有先祖RDD中的一些分區丟失,導致計算的重新執行。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的[scala-spark]8. RDD的实现和编程接口的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL SERVER与ACCESS、EX
- 下一篇: 强烈谴责中国红十字会