【spark】關於spark的shuffle模式的一些見解

我不想說太多源碼層面的東西,然後把詳細方法一個個列出來,其實沒有多大意義(因爲源碼裏有,再者比我講的清晰明白的大有人在,我沒有必要再重複相同的東西),但是我真的花了好大的精力才把這部分看完,我得記錄下,不然會忘掉

 

一、spark到底有幾種shuffleManager(shuffle管理類)可以選擇?

首先spark早期的版本(比如1.5.1版本),是有三種shuffle

http://spark.apache.org/docs/1.5.1/configuration.html#shuffle-behavior

但是後來在1.6的版本又把tungsten-sort取消掉了,最後在2的版本又把hash去掉了

 所以現在的版本只有一種了!!!雖然配置裏可以寫sort或者tungsten-sort,但是指向的是同一個類

sparkEnv類中:

 

二、shuffle模式有幾種?

首先是構建shufflehandle(shuffle處理器),獲得write寫出數據(這當中還有一些排序,spill磁盤,磁盤上多個文件合併等,我就不具體說了,很多文章都有說明)

 

1、構建處理器

SortShuffleManager類中:

有一個註冊shuffle的方法,這個方法是在DAG構建的時候會觸發的(對,就是那個面試的時候很愛問的寬依賴和窄依賴!)

我們可以看到這個方法裏會構建3中ShuffleHandle(handle是處理的意思,所以就是有三種shuffle的處理方式)

 然後我們先來看看各自的條件

(1)、BypassMergeSortShuffleHandle

(這個類的名字就是繞過聚合和排序,取名很有哲學!)的生成條件如下:

1、依賴中是否有map端的聚合?(必須沒有)

2、依賴的分區數是否小於spark.shuffle.sort.bypassMergeThreshold這個值(默認是200)

我多說一句,spark.shuffle.sort.bypassMergeThreshold建議不要隨便改動,因爲沒有聚合,spark會直接往磁盤上寫數據,200就要開啓200個io流,如果你手動設置調大了,就會開啓更多的io流,所以值不能太大,會出問題

 

(2)、SerializedShuffleHandle

(看的出來,序列化的shuffle)的生成條件如下:

1、序列化支持relocation(這是什麼鬼東西,講實話我沒百度到),但是我可以確定的是默認的java序列化是做不了這個事情的,你需要把spark.serializer設置爲org.apache.spark.serializer.KryoSerializer,這樣就ok了!

2、依賴中沒有聚合

3、分區數小於(1 << 24) - 1,也就是16777215

 

(3)、BaseShuffleHandle

如果上兩條都失敗,那就構建BaseShuffleHandle

 

2、構建write

根據上面不同的handle創建不同的write(寫類)

SortShuffleManager類中:

好,所以對應關係是

BypassMergeSortShuffleHandle 對應 BypassMergeSortShuffleWriter

SerializedShuffleHandle 對應 UnsafeShuffleWriter 使用 ShuffleExternalSorter 做排序

BaseShuffleHandle 對應 SortShuffleWriter 使用 ExternalSorter 做排序

 

spark源碼分析之ShuffleExternalSorter(作者:weiqing687 ):https://blog.csdn.net/qq_26222859/article/details/81502251

 

3、區別和使用場景

(1)、區別

(1)、其實區別在一開始做handle判斷的時候,就可見一斑,bypass適用沒有聚合,分區少(數據量少)的情況,因此他是最先判斷的

(2)、接着是unsafe,unsafe其實是spark的tungsten計劃(可以直接操作服務器的內存,以此來避免GC和JVM裏面因爲對象構建而多佔用的資源),但是有三個前提條件,就是使用kryo和沒有聚合操作外加分區數要小於16777215(不過說句實在話,分區數要大於1600W的任務。。。我還真沒見過,可能我孤陋寡聞了)

(3)、最後這種應該是最通用的了,在以上兩條都不滿足的時候,只能觸發(沒有任何強化特性的)基礎shuffle,他就沒有什麼限制條件了,啥都能做,什麼聚合啊排序啊,或者不想聚合啊都ok,原因在於

SortShuffleWrite類中的write方法:

會根據是否有聚合和排序構建ExternalSorter,然後ExternalSorter類insertAll方法裏,又會判斷聚合與否,來選擇是使用spark自定義的map保存數據還是buffer緩衝數據(map是可用聚合更新數據的,buffer只是緩衝,然後預估這兩個對象的大小,來spill磁盤)

 

 

(2)、使用場景

相信我,這篇文章你能讀到這裏,我已經覺得你很棒了!因爲我自己都覺得很枯燥,好像對於那些想做shuffle層面優化的小夥伴來說,啥都沒得到,接下來我要說說我自己看了這些知識之後的觀點。

1、map端的聚合的疑問?

map端的聚合其實是一個優化,他可以減少數據佔用的空間,10條(spark,1)這樣的數據,我可以用1條(spark,10)來代替,肯定是方便的,但是可以看到如果想使用unsafe的shuffle,那就不能有map端的聚合,那到底有哪些場景適用呢?

我舉幾個例子:

RDD:groupbyKey

是不是覺得,太少了,之前我一時之間也想不到其他的,不過後來

repartitionsort排序,還有一個非常常見的場景join

2、unsafe和基礎的shuffle性能

在完全相同的數據量和處理下,unsafe的性能肯定會比基礎的shuffle性能好,不然spark就不用那麼大費周折的添加這個功能,但是不少場景下,我們是可以通過map的先行聚合來減少數據量,既然減少了數據量,那麼相應內存消耗,io消耗就會減少,因此不能說所有場景下unsafe的性能都比基礎的shuffle好

3、bypass基本只使用數據量少的場景

像本地測試,基本上全是走bypass,大家可以自己在註冊shuffle的方法打斷點跑跑看

4、想使用unsafe優化,是否必須顯示設置kryo

我自己試下,rdd編程的話,必須設置,否則就走java的序列化,那就永遠都用不到unsafe

但如果你用的是DataSet的DSL編程,我發現不設置kryo,他也會走到unsafe裏,不過管他的呢,你直接在配置文件裏寫死kryo它不香嗎?

 

以上就是我對spark的shuffle模式的總結和見解,歡迎大家留言討論!!

我也看到一些文章還不錯,所以留在下面:

Spark中幾種ShuffleWriter的區別你都知道嗎?(作者:叫我不矜持):https://www.jianshu.com/p/cbab289d51c0

Spark SortShuffleWriter(作者:wangdy12):https://www.jianshu.com/p/541b3648ffd7

spark源碼分析系列(作者:JohnnyBai):https://www.cnblogs.com/johnny666888/p/11259944.html

菜雞一隻,一晃今天是2020年上半年的最後一天了,感覺好快啊~

感謝“甘木”大佬的點撥,我才能寫出這篇文章!

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