shuffle原理及調優

一、原理概述

①什麼是shuffle?

以reduceByKey爲例,要把分佈在集羣各個節點上的數據中的同一個key對應的values集中到一塊,集中到集羣中同一個節點上。更嚴格地說,集中到同一個節點的同一個executor的task中。

集中同一個key對應的values之後,數據變成<key,Iterable<value>>,算子函數對values進行reduce操作,最後變成<key,value>形式的數據。

每一個shuffle的前半部分stage的task,都會創建與下一個stage的task數量相同的文件。比如下一個stage有100個task,那麼當前stage的每個task都會創建100個文件。並且,會將同一個key對應的values寫入同一個文件;不同節點上的task,會將同一個key對應的values,寫入下一個stage同一個task對應的文件中。在這個部分,task在將數據寫入磁盤文件之前,會先寫入內存緩存區,內存緩衝區溢滿後,再spill溢寫到磁盤文件中。

shuffle的後半部分stage的task,每個task都會從各個節點中,上一個stage中的task爲自己創建的文件中,拉取屬於自己的key,value數據,然後task會有一個內存緩衝區,對數據進行匯聚。

②有哪些常用的操作會觸發shuffle?

spark中,常見的會觸發shuffle的算子有:groupByKey、reduceByKey、countByKey、join,等等。

二、合併map端輸出文件

在該功能不開啓的情況下,如原理所述,當前stage的每個task都會爲下一個stage創建和下一個stage中task數量相同的文件。比如當前stage和下一個階段的stage都有10個task,那麼當前stage的每個task會爲下一個stage創建10個文件,一共是10*10=100個文件。

開啓該功能後,如果每個executor只有兩個cpu core,那麼同時運行的task數量只有2個。這個時候,當前的stage中,先運行2個task,每個task創建10個文件,一共是2*10=20個。這2個task運行完之後,再運行後面的2個task。後面的2個task運行的時候,不再創建新的文件,而是複用前面2個task創建的文件。依次類推,直到當前stage的10個task運行結束,一共創建20個文件,和之前的100個文件相比,數量大大減少,需要寫到磁盤的文件數減少,同時下一個stage階段需要去磁盤上讀取的文件數也減少,性能得到很大提升。

該功能默認不開啓,可以在代碼中使用new SparkConf().set("spark.shuffle.consolidateFiles", "true")來開啓。

三、調節map端內存緩衝和reduce端內存佔比

默認情況下,map端每個task內存緩衝的大小是32kb,reduce端內存佔比是0.2,即20%。

如果需要處理的數據量比較大,比如每個task需要處理320000kb,那麼需要向磁盤溢寫320000/32=10000次,向磁盤溢寫文件次數過多,造成大量的磁盤IO,性能下降。

reduce端拉取數據的時候,如果數據量很大,而內存佔比很小,在reduce端聚合的時候,內存不夠用,需要spill溢寫到磁盤中。向磁盤溢寫的數據量越大,後續處理需要從磁盤讀取的數據量也越大。這樣頻繁地發生磁盤IO,會嚴重地影響性能。

根據上述情況,爲了減少磁盤IO,可以調節map端緩存區大小和reduce端內存佔比。

調節的原則是,先固定一個參數,調整另一個參數,多次銷量調節。一個參數調整完之後,再調整另一個參數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章