0x01 數(shù)據(jù)序列化調(diào)優(yōu)
在進(jìn)行RDD緩存和Shuffle過程時抄邀,Spark會將數(shù)據(jù)對象進(jìn)行序列化宣鄙,所以選擇合適的序列化方法写烤,可以提高spark任務(wù)的性能焰扳。SPark提供了兩個序列化庫:
原生Java序列化:默認(rèn)情況下Spark使用Java序列化庫。Java序列化很靈活藐石,但是通常很慢即供,而且序列化格式很大。
Kryo序列化:與Java序列化相比于微,kryo速度更快(10倍左右)逗嫡,而且序列化格式更緊湊办素,序列化后數(shù)據(jù)包體更小。
使用:conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
祸穷,如果對象很大性穿,還需要增加spark.kryoserializer.buffer
的大小。
0x02 內(nèi)存調(diào)優(yōu)
2.1調(diào)整數(shù)據(jù)結(jié)構(gòu)
1.如果Executor分配的內(nèi)存少于32G雷滚,可以設(shè)置JVM標(biāo)識:-XX:+UseCompressedOops將對象指針設(shè)為4字節(jié)而不是8字節(jié)需曾。
2.2 序列化RDD存儲
對于重復(fù)使用的RDD,將它緩存起來祈远。
2.3 垃圾收集優(yōu)化
1.Spark的Storage和Execution內(nèi)存占用由spark.memory.fraction控制呆万,應(yīng)該保證JVM的老年代的占用比例(NewRatio/(NewRatio+1))大于spark.memory.fraction。這樣能夠保證老年代有足夠的空間存放RDD緩存和Shuffle緩存的數(shù)據(jù)车份,避免頻繁Full GC谋减。
2.通過設(shè)置-XX:+UseG1GC來使用G1垃圾回收器。在堆內(nèi)存夠大時扫沼,需要通過設(shè)置-XX:G1HeapRegionSize來增大G1區(qū)域大小出爹。
3.如果任務(wù)是從HDFS中讀取數(shù)據(jù),通常每個HDFS數(shù)據(jù)塊(128M)對應(yīng)一個RDD的Partition(或者一個Task),解壓縮塊的大小通常是塊大小的2~3倍缎除,而且每個Executor通常同時運行3 ~ 4Task严就,所以我們可以估計Eden的大小為4*3*128MB。
0x03 其他調(diào)優(yōu)
3.1 并行度調(diào)優(yōu)
最理想的情況:Task數(shù)量和分配的CPU core數(shù)量相同器罐,這樣所有的Task一起運行梢为,差不多同一時間運行完畢。
但實際情況轰坊,有些task會運行的快一些铸董,有些task會運行的慢一點,如果task數(shù)量和cpu core的數(shù)量相同肴沫,就會導(dǎo)致一部分task運行完后粟害,這部分cpu core就空閑出來了,而且一直空閑到程序結(jié)束樊零,就造成了資源浪費我磁。所以官方推薦Task數(shù)量設(shè)置成CPU core數(shù)量的2~3倍。盡量讓cpu不要空閑驻襟,同時提高Task的并發(fā)度,可以減少每個task處理的數(shù)據(jù)量芋哭,從而也可以提升運行性能沉衣。
3.2 減少Task的內(nèi)存使用量
Spark自動根據(jù)文件的大小設(shè)定了運行在其上的map任務(wù)的數(shù)量,而對于reduce操作减牺,例如groupByKey和reduceByKey豌习,如果并行度過低存谎,導(dǎo)致Task中的數(shù)據(jù)集太大档礁,進(jìn)而導(dǎo)致OutofMemoryError憨攒。我們可以增加并行度,讓每個人物獲取到的數(shù)據(jù)集更小搀绣。而且多任務(wù)可以重用一個Executor JVM栋艳,任務(wù)的啟動成本很低恰聘,因此可以安全地增加并行度到集群中的core數(shù)量。
3.3 廣播大變量
當(dāng)RDD算子中引用了Driver中的一個大的對象吸占,每個Task都會持有這個大對象的序列化副本晴叨,導(dǎo)致Task序列化包體太大,可以通過Spark的廣播機(jī)制矾屯,將大對象廣播到每個Executor上兼蕊,這樣可以減少Task的序列化包體。一般來說大于20kb的Task有可能需要優(yōu)化件蚕。