1. 程式人生 > >Spark的Shuffle原理(一):HashShuffle

Spark的Shuffle原理(一):HashShuffle

01.HashShuffle相關知識

    Spark Shuffle類似於MapReduce的過程,在Spark 的1.0版本以前,Spark採用的是Hash Shuffle,與MapReduce不同的是,Hash Shuffle沒有排序過程。Shuffle階段主要發生在寬依賴階段,什麼是寬依賴呢?

    上圖中,可以很好的理解寬依賴和窄依賴,對於一般的join、groupByKey等運算元都會產生寬依賴。網上流傳的一句話:

    寬依賴:可以理解為超生,就是一對多、多對多的關係。

    窄依賴:可以理解為獨生子女,就是一對一、多對一的關係。

    針對於Shuffle階段,一般涉及到調優和效能優化,所以理解Shuffle的過程非常重要。

02.Hash Shuflle V1.0的原理

    本文將結合下圖講解HashShuffle的原理:

    HashShuffle主要分為兩個階段,主要是Shuffle Write和Shuffle Read階段;在Shuffle的上端,我們可以類似的將這個階段稱之為Map端,在Shuffle的下游,我們可以稱這個階段稱以為Reduce端;在ShuffleWrite階段,Map端主要

是根據Reduce端的Task數量,根據Hash函式取模(結合上圖,這個Reduce端Task的數量是3個),將資料分為3份,每一份都有一個bucket來儲存小檔案;每一個Bucket最後將這些檔案寫入到本地磁碟的ShuffleBlockFile中,形成一個FileSegement檔案;所以產生的檔案的數量是MapTask數量*ReduceTask數量;結合上圖,這裡有4個MapTask,下游有3個ReduceTask,所以產生的4*3=12份資料。

    Shuffle Read階段,Recude端的Task根據自己的分割槽號,去上游每一個Bucket拉去資料,然後使用fetch操作,將這些小檔案合併成為一個大檔案(需要注意的是,這裡的檔案存放在記憶體中,有可能記憶體放不下,這也是後來Spark放棄使用這種Shuffle的原因之一)。

02.HashShuffle V1.0的缺點以及優化策略

    上一節分析了HashShuffle V1.0的原理,每一個MapTask階段都會產生和下游ReduceTask個數相同的小檔案和bucket,這樣會導致記憶體需要儲存大量的檔案的描述符,針對於海量的小檔案到磁碟,涉及大量的IO操作,同時由於JVM記憶體不足也會導致多次GC;在這些檔案的傳輸過程中,會涉及序列化和反序列化的過程,這是比較消耗時間的,在ReduceTask拉去資料處理時,需要將資料存放在記憶體內,如果檔案量足夠大,記憶體無法儲存,可能導致OOM錯誤。

    那麼,如何解決上述的問題呢?

    Spark提供了另一個種Shuffle,叫做ConsolidatedShuffle,該Shuffle主要以Executor為單位,進行檔案的處理,具體過程如下:

    上圖中,每一個Executor產生和下游ReduceTask個數相同的bucket,產生的檔案數量是Executor數量*ReduceTask個數;當MapTask階段寫檔案到磁碟,就是Executor的Core數量*RecueTask數量writehadler;ConsolidatedShuffle僅僅只是解決了檔案數量的問題,在磁碟寫入的方面沒有很大的優化。

    ConsolidatedShuffle的缺點:

    1.ShuffleRead階段和V1.0階段一樣,也有OOM問題

    2.在ShuffleWrite階段,檔案刷到磁碟時依舊需要使用大量的I/O操作。