9.Shuffle讀寫源碼分析

來源:互聯網
上載者:User
先直接上原理圖吧 ! ShuffleMapTask在計算資料之後會為每一個ResultTask建立一份bucket緩衝 , 以及對應的ShuffleBlockFIle磁碟檔案進行儲存 , 在計算完之後會將計算過的相應資訊放入MapStatus , 最後發送給Driver中的DAGScheduler的MapOutputTracker , 每個ResultTask會用BlockStoreShuffleFetcher去MapOutputTracker中的MapStatus擷取需要拉取的資料 , 然後通過底層的BlockManager將資料拉取過來 , 拉取過來的資料就會組成一個內部的RDD , 叫ShuffleRDD , 存入緩衝 , 緩衝不夠存入磁碟 , 最後ResultMap對資料進行彙總產生MapPartitionRDD , 也就是我們所寫程式中action操作後結果RDD

最佳化後的shuffle分析原理圖:




最佳化後的shuffle原理就是根據cpu的數量在ShuffleMap寫入資料到磁碟檔案時只會建立於cpu相應的檔案資料 , 後面在運行新的ShuffleMapTask的時候也只會向同樣的檔案中寫入資料 , 同時會記錄下一些索引來記錄哪個ShuffleMapTask計算的資料在ShuffleBlockFile中的位置 , 多個ShuffleMapTask寫入的資料就叫做一個segment , 也就是說原來的100個ShuffleMapTask對應的100個ResulTask時會建立100*100個磁碟檔案 , 而現在只需要cpu數量乘以ResultMap的數量之積檔案數 , 減少了大量的磁碟檔案讀寫 , 這種最佳化shuffle的方式只需在建立SparkContext的時候設定一個參數即可
在上一章節關於Task的源碼分析最後的關於writer的代碼中:
writer . write ( rdd . iterator ( partition , context ). asInstanceOf [ Iterator [ _ <: Product2 [ Any , Any ]]])

其實這個writer預設的情況下就是HaspShuffleWriter , 調用writer的方法源碼如下:

                              /** Write a bunch of records to this task's output */                  /**                   * 將每個ShuffleMapTask計算出來的新的RDD的partition資料寫入本地磁碟                   */                  override def write(records: Iterator[_ <: Product2[K, V]]): Unit = {                    // 首先判斷,是否需要在map端進行本地彙總                    // 比如reduceByKey這樣的運算元操作的話它的dep.aggregator.isDegined就是true , 包括def.mapSideCombine也是true                    val iter = if (dep.aggregator.isDefined) {                      if (dep.mapSideCombine) {                        // 這裡就會執行本地彙總,比如(Hi,1)(Hi,1)那麼此時就會彙總成(Hi,2)                        dep.aggregator.get.combineValuesByKey(records, context)                      } else {                        records                      }                    } else {                      require(!dep.mapSideCombine, "Map-side combine without Aggregator specified!")                      records                    }                                    // 如果進行本地彙總那麼就會遍曆資料 , 對每個資料調用partition預設是HashPartition , 產生bucketId                    // 也就決定了每一份資料要寫入哪個bucket                    for (elem <- iter) {                      val bucketId = dep.partitioner.getPartition(elem._1)                      // 擷取到了bucketId之後就會調用ShuffleBlockManager.formapTask()方法來產生bucketId對應的writer,然後用writer將資料寫入bucket                      shuffle.writers(bucketId).write(elem)                    }                  }              

這裡的shuffle是HushShuffleWriter的一個成員變數 , 通過shuffleBlockManager對象的forMapTask方法擷取每個bucketId對應的writer , forMapTask方法源碼如下:
                              /**                   * 給每個map task擷取一個ShuffleWriterGroup                   */                  def forMapTask(shuffleId: Int, mapId: Int, numBuckets: Int, serializer: Serializer,                

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.