1. 程式人生 > >Hadoop Shuffle和Spark Shuffle的區別

Hadoop Shuffle和Spark Shuffle的區別

一.MR的Shuffle
  mapShuffle
       資料存到hdfs中是以塊進行儲存的,每一個塊對應一個分片,maptask就是從分片中獲取資料的
       在某個節點上啟動了map Task,map Task讀取是通過k-v來讀取的,讀取的資料會放到環形快取區,這樣做的目的是為了防止IO的訪問次數,然後環形快取區的記憶體達到一定的閥值的
       時候會把檔案益寫到磁碟,溢位的各種小檔案會合併成一個大檔案,這個合併的過程中會進行排序,這個排序叫做歸併排序
   1.1map階段會涉及到
      1.1.1.sort排序(預設按字典排序)
      1.1.2.合併(combiner合併)
      1.1.3.檔案合併(merage 合併 總共有三種,預設是記憶體到磁碟)
      1.1.4.壓縮(設定壓縮就會執行)
  reduce Shuffle
       歸併排序完成後reduce端會拉取map端的資料,拉取的這個過程叫做copy過程,拉取的資料合併成一個檔案,GroupComparator(預設,這個我們也可以自定義)是專門對資料夾裡面的key進行分組
       然後就形成k-List(v1,v2,v3)的形式,然後reduce經過業務處理,最終輸出到hdfs,如果設定壓縮就會執行,不設定則不執行
   1.2 reduce階段會涉及到:
      1.2.1.sort排序
      1.2.2.分組(將相同的key的value放到一個容器的過程)
      1.2.3.merge檔案合併
      1.2.4.壓縮
二.spark shuffle的版本一
      2.1.rdd中一個partition對應一個shufflemapTask任務,因為某個節點上可以有多個分割槽,所以可以有多個shufflemapTask
      2.2.每一個shufflemapTask都會為每一個resultTask建立一個bucket快取(記憶體),bucket的數量=M x R,當記憶體達到一定值的時候會益寫到shuffleblockfile檔案中
      2.3.shuffleMap task會封裝成一個叫mapStatus,這個mapstatus裡面包含了每一個resultTask拉取資料的大小
      2.4 Mapstatus: 是ShuffleMapTask返回排程器scheduler的物件,包括任務執行的塊管理器地址和對應每個reducer的輸出大小。
          如果partitions的數量大於2000,則用HighlyCompressedMapStatus,否則用CompressedMapStatus。
      2.5.每一個resultTask拉取過來的資料,就會在內部形成一個rdd,這個rdd叫做shuffleRdd,這個rdd的資料優先存放到記憶體中,記憶體中不夠然後存到磁盤裡
          如果是groupByKey運算元就結束了,下次執行ReduceByKey的時候,再進行相同key的聚合操作,這個時候會把shuffle rdd進行聚合操作生成mapPartitionRdd,就是我們執行reduceByKey之後得到的那個rdd
spark shuffle的版本二
      缺點:版本一的shuffle方式中會產生大量的小檔案,
      版本二的優點:就是為了減少這麼多小檔案的生成,bucket的數量=cpu*resultTask的個數
      版本二設計的原理:一個shuffleMapTask還是會寫入resultTask對應個數的本地檔案,但是當下一個shuffleMapTask執行的時候會直接把資料寫到之前已經建立好的本地檔案,這個檔案可以複用,這種複用機制叫做consolidation機制
      我們把這一組的shuffle檔案稱為shuffleGroup,每個檔案中都儲存了很多shuffleMapTask對應的資料,這個檔案叫做segment,這個時候因為不同的shuffleMapTask都是存在一個檔案中
      所以建立索引檔案,來標記shuffleMapTask在shuffleBlockFile的位置+偏移量,這樣就可以在一個檔案裡面把不同的shuffleMaptask資料分出來
spark shuffle的版本三
       版本三的優點:是通過排序建立索引,相比較於版本二,它只有一個臨時檔案,不管有多少個resultTask都只有一個臨時檔案,
       缺點:這個排序操作是一個消耗CPU的操作,代價是會消耗很多的cpu
       版本二佔用記憶體多,開啟檔案多,但不需排序,速度快。版本三佔用記憶體少,開啟檔案少,速度相對慢。實踐證明使用第二種方案的應用場景更多些。
三、shuffle的讀流程
       1.有一個類blockManager,封裝了臨時檔案的位置資訊,resultTask先通過blockManager,就知道我從哪個節點拿資料
       如果是遠端,它就是發起一次socket請求,建立一個socket連結。然後發起一次遠端呼叫,告訴遠端的讀取程式,讀取哪些資料。讀到的內容再通過socket傳過來。
       2.一條條讀資料和一塊塊讀資料的優缺點?
             2.1如果是一條條讀取的話,實時性好,效能低下
             2.2一塊塊讀取的話效能高,但是實時性不好
       Shuffle讀由reduce這邊發起,它需要先到臨時檔案中讀,一般這個臨時檔案和reduce不在一臺節點上,它需要跨網路去讀。但也不排除在一臺伺服器。不論如何它需要知道臨時檔案的位置,
      這個是誰來告訴它的呢?它有一個BlockManager的類。這裡就知道將來是從本地檔案中讀取,還是需要從遠端伺服器上讀取。
       讀進來後再做join或者combine的運算。
       這些臨時檔案的位置就記錄在Map結構中。
       可以這樣理解分割槽partition是RDD儲存資料的地方,實際是個邏輯單位,真正要取資料時,它就呼叫BlockManage去讀,它是以資料塊的方式來讀。
       比如一次讀取32k還是64k。它不是一條一條讀,一條一條讀肯定效能低。它讀時首先是看本地還是遠端,如果是本地就直接讀這個檔案了,
       如果是遠端,它就是發起一次socket請求,建立一個socket連結。然後發起一次遠端呼叫,告訴遠端的讀取程式,讀取哪些資料。讀到的內容再通過socket傳過來。