大數據(十三)--初識SparkCore之RDD(彈性分佈式數據集)&Operation(算子)

  在開始學習Spark工作原理之前, 先來介紹一下Spark中兩個最爲重要的概念-- 彈性分佈式數據集(Resilient Distributed Datasets, RDD) 和算子(Operation).

RDD背景

  Spark的核心是建立在RDD之上, 使Spark中的各個組件可以無縫進行集成, 從而在一個應用程序中完成大數據計算. 這也是爲什麼說在SparkCore中一切得計算都是基於RDD來完成的. RDD的設計理念源自AMP實驗室發表的論文–Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing.

  MapReduce計算框架在實際應用中, 許多迭代式算法和交互式數據挖掘過程中的計算結果會寫到磁盤, 然後再重複使用, 這就帶來了大量的磁盤IO和序列化開銷. 爲解決中間過程數據落地花費大量時間的需求, 出現了一種抽象的數據結構, 讓我們不必再考慮數據的分佈式特性, 只需保存具體的邏輯轉換表達式即可, 這種數據結構就是RDD.

  RDD之間的轉換操作使父子RDD之間具有依賴關係, 滿足條件的RDD之間形成管道(Pipeline), 從而避免中間結果落地, 極大的降低了磁盤IO和序列化消耗的時間.

RDD介紹

  RDD(彈性分佈式數據集), 雖然叫做數據集, 但RDD並不像集合一樣存儲真實的數據, 而是存儲這些數據轉換的邏輯, 可以將RDD理解爲一個大的數據集合以分佈式的形式保存在集羣服務器的內存中. 每個RDD可以分成多個分區, 每個分區就是一個數據集片段, 並且一個RDD的不同分區可以被保存到集羣中不同的節點上(但是同一個分區不能被拆分保存), 從而可以在集羣中的不同節點上進行並行計算.

  RDD提供了一種高度受限的共享內存模型, 即RDD是隻讀的記錄分區的集合, 不能直接修改, 只能基於穩定的物理存儲中的數據集來創建RDD, 或者通過在其他RDD上執行轉換操作(如map、join和groupBy) 創建得到新的RDD.

Operation介紹

  算子(Operation)是Spark中定義的函數, 用於對RDD中的數據結構進行操作和轉換等. Spark中的算子可以分爲4類:

  1. 創建類(creation)算子, 用於將內存中的集合或外部文件創建爲RDD.
  2. 轉換(transformation)算子, 用於將一種格式的RDD轉換爲其他自定義格式.
  3. 緩存(cache)算子, 用於將RDD緩存在內存(memory)或磁盤(disk)中, 一般後續計算會用到重複數據時纔會使用.
  4. 行動(action)算子, 用於觸發執行Spark作業, 並將計算結果保存爲集合, 標量或保存到外部文件, 數據庫中.

  典型的RDD執行過程如下:
在這裏插入圖片描述

  1. 讀入外部數據源(或者內存中的集合) ,然後Create RDD;
  2. RDD經過一系列Transformation, 每一次都會產生不同的RDD, 供給下一個Transformation 使用;
  3. 最後一個RDD經Action進行處理, 得到最後想要的值, 並進行後續輸出操作.

  需注意: RDD採用惰性調用, 即在RDD的執行過程中, 如圖所示, 真正的計算髮生在RDD的Action操作, 對於Action之前的所有Transformation操作, Spark只是記錄下Transformation操作應用的一些基礎數據集以及RDD生成的軌跡, 即相互之間的依賴關係, 而不會觸發真正的計算.

  RDD提供的轉換接口都非常簡單, 都是類似map, filter, groupBy, join等粗粒度的數據轉換操作, 而不是針對某個數據項的細粒度修改. 因此, RDD比較適合對於數據集中元素執行相同操作的批處理式應用, 而不適合用於需要異步/細粒度狀態的應用, 比如Web應用系統, 增量式的網頁爬蟲等.

  轉換和行動兩種類型的算子, 前者指定RDD之間的相互依賴關係, 後者用於執行計算並指定輸出的形式. 兩類操作的主要區別是, 轉換操作接受RDD並返回RDD, 而行動操作(如count、collect等) 接受RDD但是返回非RDD(即輸出一個值或結果).

RDD五大特性

  1. RDD是由一系列的Partition(分區)組成;
  2. 一個函數作用在每一個分區上;
  3. RDD之間存在依賴關係;
  4. [可選項]分區器作用在KV格式的RDD上;
  5. [可選項]RDD會提供最佳計算位置.

  接下來, 結合Spark實現的WC案例, 來理解這五個特性以及其他注意點(圖中綠色爲block塊, 藍色爲Partition分區):
在這裏插入圖片描述

  • HDFS存儲文件是以block塊的形式, Spark應用在讀取HDFS上的數據後, 會將同一個block塊中的數據轉換邏輯保存在同一個Partition中, 一個文件對應的所有Partition構成一個RDD. 即一個RDD中的Partition個數等於這個文件存儲在HDFS中的block個數. 但有一個例外, 如果一個block塊的最後存儲了某個數據的大部分字節後達到block規定的大小, 僅有少量字節存儲在另外一個block塊中, 這時這多餘的小部分數據會放在與大部分數據相同的Partition中, 即Partition數小於block塊數.
  • Spark中沒有讀文件的方法, 但Spark依然能夠讀取文件內容依賴的是MapReduce中讀文件的方法. MR讀文件前, 會先將文件劃分爲一個個的split(切片), 一個split的大小 = 一個block的大小; 但這個文件的split個數 ≈ 存儲這個文件的block個數(同上一個例外情況); 一個RDD中Partition的個數 = 這個文件切分的split個數.
  • 每一個函數作用在每一個分區上, 即每個函數會在每一個Partition中各執行一次.
  • RDD之間存在依賴關係, 通過一個算子關聯的兩個RDD稱爲父子RDD, 父子RDD之間存在寬窄依賴(後續講解), 子RDD知道它的父RDD是誰, 但父RDD不知道它的子RDD有誰. 這種依賴關係的優勢在於當數據因某種情形丟失時, 可以通過算子和父RDD重寫計算出子RDD, 從而提高了計算的容錯性. (RDD的依賴關係也被稱爲RDD的血統–Lineage)
  • KV格式的RDD指RDD中的數據是二元組類型, 對於這類RDD可以使用分區器按照Key或者Value進行分組, 進而完成聚合計算. 在WC中, pairRDD和restRDD均爲KV格式的RDD. 分區器用於決定數據被放到哪一個reduce task中處理.
  • 每一個算子作用在每一個Partition上, Partition會分佈式的存儲在集羣各個節點的內存中, 對一個Partition的連續處理可以看作是一個task任務, 每一個task計算任務都在數據所在節點上執行, 從而實現數據本地化, 減少網絡IO. 簡單來說, RDD會提供一個方法接口, 調用這個接口就能直接拿到這個RDD所有Partition的位置, 拿到位置之後就可以分發task了. 至於這個接口是什麼不需要我們關心, Spark應用在執行時會自動尋找.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章