Spark性能調優之道——解決Spark數據傾斜(Data Skew)的N種姿勢
原文:http://blog.csdn.net/tanglizhe1105/article/details/51050974
背景
很多使用Spark的朋友很想知道rdd裏的元素是怎麽存儲的,它們占用多少存儲空間?本次我們將以實驗的方式進行測試,展示rdd存儲開銷性能。
關於rdd的元素怎麽存儲,Spark裏面實現了好幾種不同類型的rdd,如最常見的MapPartitionsRDD,它處理map,filter,mapPartition等不引起shuffle的算子;再如ShuffledRDD它由shuffle操作生成的;像GraphX裏面的VertexRDD、EdgeRDD和TripletRDD,它們是分區內構建了大量索引得rdd。不同的rdd擁有不同的元素存儲機制,這些機制由rdd具體的分區對象來實現。關於rdd分區對象的存儲方式,由於內容過多,這裏不便介紹。
測試方法論
rdd到底占用多少空間,使用spark web ui的Executors查看是不夠的,它只能顯示executor目前已使用內存空間大小,並不能跟蹤每個rdd空間使用情況。好在spark提供了cache功能,它能使我們手動控制rdd在內存中貯存。若另外一個rdd使用已cache的rdd,那麽它的輸入便是cached rdd,rdd的輸入在web ui的job信息裏是可以查看的。本實驗的主要方法便是如此
val a = sc.parallelize( 1 to 1024*1024, 1).cache()
a.count()
val b = a.map( x=> (x, x)).cache()
b.count()
val c = b.map(x => x)
c.count()
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
那麽b.count()提交的job的輸入能查看rdd a占用的內存空間大小,c.count()使得我們能查看rdd b占用的內存空間大小。
結果
元素數目 | 元素類型 | rdd占用空間大小 |
---|---|---|
1M | Int | 32MB |
1M | (Int, Int) | 48MB |
1M | (Int, Int, Int) | 120MB |
1M | Long | 32MB |
1M | (Long, Long) | 56MB |
1M | (Long, Long, Long) | 120MB |
1G | Int | 32GB |
1G | (Int, Int) | 48GB |
1G | (Int, Int, Int) | 120GB |
1G | Long | 32GB |
1G | (Long, Long) | 56GB |
1G | (Long, Long, Long) | 120GB |
10G | Int | 240GB |
10G | Long | 246.7GB |
本實驗1M使用單個分區,1G使用80個分區(10個節點),10G使用144個分區(18個節點)
1M與1G元素規模的結果吻合的太好了,以至於我都有不敢相信,可是測試出來的結果就是這樣的,這也證明spark在數據規模可擴展性方面真是太完美了。
關於每條元素的存儲開銷,若元素是Java對象存儲,那麽每條元素至少會帶入18自己額外開銷,若以基本數據類型存儲,則不會帶入額外開銷。
測試結果有一些詭異的地方:
相同元素規模情況下,Int與Long占用空間相同,(Int, Int)與(Long, Long)不同,但(Int, Int, Int)與(Long, Long, Long)又相同。
1M Int凈存儲空間為4MB,但占用32MB空間,且占用空間一般呈整數樣式。
Spark性能調優之道——解決Spark數據傾斜(Data Skew)的N種姿勢