01_spark入門

Stitches發表於2024-07-11

Spark

Spark 作為分散式計算框架,基於 MapReduce 框架開發,但是也有以下區別:

  • Spark 基於 Scala 語言開發,MR 基於 Java 語言開發;Scala 是函數語言程式設計語言,對於函式間相互呼叫效率更高;而 Java 是面嚮物件語言,函式間呼叫必須依賴於物件,效率低。
  • MapReduce 核心是一次性計算,不適合迭代計算,因為中間結果必須存檔,後續步驟依賴於當前中間結果,會造成大量的磁碟IO,導致效率低;Spark 最佳化了執行邏輯,前一步執行的結果儲存到記憶體而不是磁碟,所以可以提取出重複的步驟,封裝成函式。
  • Spark 的 RDD(彈性分散式資料集)支援資料的自動快取,使得重複的資料可以快速訪問,無需重新從磁碟讀取。
  • Spark 和 MapReduce 各有利弊,MapReduce 因為依賴於磁碟所以能夠保證程式一定執行完畢,Spark 因為依賴於記憶體,可能會出現記憶體溢位等問題。
  • 如果舊專案是基於 Hadoop 的,現在需要遷移到 Spark,那麼就可以使用 On Yarn 模型,基於 Yarn 排程。

img

Spark 內建模組:

img

  • Spark SQL:提供 HQL 與 Spark 進行互動處理的 API,每個資料表當作一個 RDD,Spark SQL 查詢被轉化為 Spark 操作;
  • Spark Streaming:對實時資料流進行處理和控制;
  • MLib:機器學習演算法庫;
  • Graphix:控制圖、並行圖操作和計算的一組演算法和工具的集合;
  • Spark Core:底層 RDD API基礎庫,其他模組都會依賴;

RDD

RDD(Resilient Distributed Datasets,彈性分散式資料集)在 Spark 計算過程中扮演重要的角色。Spark 的計算任務始於 SparkContext 上下文物件,它負責資源的申請、任務的排程以及 RDD 的管理和建立。

RDD 特點

RDD 具有以下特點:

  • 每個 RDD 都是隻讀的,是分佈在叢集中的只讀物件的集合;
  • 一個 RDD 由多個 Partition 分割槽組成,每個分割槽可能分佈在不同節點的記憶體中;
  • RDD 之間可以執行轉換操作,轉換但是不計算,每次計算後的結果都需要儲存為新的 RDD;

RDD 操作

RDD 主要包含了以下兩種方法,透過兩種方法不斷對資料處理儲存,最終實現高效、可靠的大資料處理任務:

  • 轉換運算元:
    • 將 Scala 集合或者 Hadoop 輸入資料構造一個新的 RDD;
    • 透過已有的 RDD 產生新的 RDD;
    • 惰性執行,只記錄轉換關係不執行計算;
    • 常見操作包括 map、filter、flatmap、union、distinct、sortbykey
  • 動作運算元:
    • 透過 RDD 計算得到新的一組值;
    • 觸發真正的計算;
    • 常見操作包括 first、count、collect、foreach、saveAsTextFile 等;

比如 rdd.map(_+1).saveAsTextFile("hdfs://node01:9000") 操作,map 對應轉換,saveAsTextFile 對應計算。

RDD 依賴

RDD 中區分寬窄依賴,因為寬依賴回覆起來速度很慢。

img

窄依賴:

  • 父 RDD 中分割槽最多被一個子 RDD 分割槽使用;
  • 子 RDD 如果部分分割槽資料丟失或損壞,只需要從父 RDD 重新計算恢復;
  • 窄依賴可以並行地生成子 RDD 的分割槽,使得任務可以在多個節點上並行執行;
  • 常見操作如 map、filter、union、sample

img

寬依賴:

  • 主要發生在需要跨分割槽的資料重組或者聚合操作;
  • 子 RDD 分割槽依賴 父RDD 的所有分割槽;
  • 子 RDD 如果部分或者全部分割槽資料丟失或損壞,必須從所有父 RDD 分割槽重新計算;
  • 寬依賴會導致資料在不同的分割槽間進行洗牌,資料需要重新分配到不同的分割槽,涉及到大量的資料移動和 IO 操作,執行寬依賴時效能可能會受到影響;
  • 例如:groupByKey、reduceByKey、sortByKey、join

舉個例子

img

  • 首先透過 SparkContext 上下文物件載入 HDFS 某個目錄下的檔案;
  • 針對每一行資料按照分表符切分成多個單詞,得到新的單詞集合;
  • 對每個單詞執行 map 處理,具體就是標記次數為 1;
  • 按照 Key 值執行 Reduce 處理,將 Key 相同的所有 Value 累加求和;(程式碼中的 _ 是 Scala 語法中的佔位符)
  • 將最終結果儲存到 HDFS 下的檔案目錄。

由於每個階段都會儲存新的 RDD,所以如果某階段計算失敗,就可以利用上一個步驟的 RDD 結果重新執行計算,而不需要從源頭開始計算。

Spark 程式

程式架構

Spark 也是主從架構,包含管理節點 Master、工作節點 Worker。
img

img

  • 構建執行環境,Driver 建立 SparkContext 上下文;
  • SparkContext 向資源管理器(standalone、Mesos、Yarn)申請 Executor 資源,資源管理器啟動 StandaloneExecutorBackend
  • Executor 向 SparkContext 申請 Task;
  • RDD 物件構建成 DAG 圖,DAG Scheduler 將 DAG圖解析為 Stage,每個 Stage 對應一個 TaskSet,然後將其傳送給 TaskScheduler,由 TaskScheduler 排程傳送給 Executor 執行;
  • Task 在 Executor 執行完畢後釋放資源;

Spark 作業執行模式

Local 模式:

Spark 應用以多執行緒方式執行在本地,方便除錯。

  • local:啟動一個 Executor;
  • local[k]:啟動 k 個 Executor;
  • local[*]:啟動 CPU 核數個 Executor;

standalone 模式:

分散式叢集執行,不依賴於第三方資源管理系統(Yarn、Mesos等)。

  • 採用 Master-Slave 結構;
  • Driver 執行於 worker,Master 只負責叢集管理;
  • Driver 向 Master 申請作業執行所需資源,Master 分配 Executor 給 Driver;
  • Driver 將解析後的 Task 排程到 Executor 上執行,並且不間斷監聽執行情況,彙報給 Master;
  • 整體架構類似於 Yarn,其中 Master——ResourceManagerDriver——ContainerExecutor——ApplicationMaster
  • 為了避免 Master 單點故障,由 Zookeeper 負責 Master 節點叢集高可用。

Spark On Yarn:

分散式部署叢集、資源、任務監控由 Yarn 管理,目前僅支援粗粒度資源分配方式。

img

這種模式的工作流程:

  • Driver 解析 Spark 資料生成一定量的 Task,然後需要開始申請 Hadoop 資源;
  • 但是 Dirver 無法申請,需要藉助 ApplicationMaster 申請,所以在 Driver 外部套用一個 ApplicationMaster 用作資源申請;
  • ApplicationMaster 透過向 ResourceManager 申請 Container 資源,到手後通知 Driver;
  • Driver 將解析好的作業分發到 Container 節點上執行。

Yarn 包括 Yarn-Client(適用於互動和除錯)、Yarn-Cluster(適用於生產環境)兩種模式。

程式執行及底層邏輯

生成邏輯執行計劃

透過 Scala 語言編寫 Spark 邏輯查詢計劃:

sc.textFile(inputArg)
  .flatMap(_.split("\t"))
  .map((_,1))
  .reduceByKey(_+_)
  .saveAsTextFile(outArg)

上述是一個 WordCount 程式的邏輯執行計劃,每個階段會生成一個單獨的 RDD。

img

生成物理執行計劃

物理查詢計劃關注於底層資料狀態:

  • 如圖一個 RDD 有 4個 Partition,那麼前三個 RDD 步驟作用於 RDD 迭代變換;這三個步驟可以劃分到一個 Stage,因為可以多個分割槽並行執行(生成 4 個任務分別排程到不同計算節點);
  • 接著第四個 RDD 步驟需要進行 shuffle,所以需要單獨劃分 Stage(可以生成 3個任務排程到不同計算節點上執行);

img

任務排程與執行

將各個階段生成的 Task 排程到 Executor 上執行,執行過程中會不停向 Driver 彙報進度。

img