您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關spark-JVM的調優原理是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
性能調優
常規性能調優:分配資源、并行度。。。等
JVM調優(Java虛擬機):JVM相關的參數,通常情況下,如果你的硬件配置、基礎的JVM的配置,都可以的話,JVM通常不會造成太嚴重的性能問題;反而更多的是,在troubleshooting中,JVM占了很重要的地位;JVM造成線上的spark作業的運行報錯,甚至失敗(比如OOM)。
shuffle調優(相當重要):spark在執行groupByKey、reduceByKey等操作時的,shuffle環節的調優。這個很重要。shuffle調優,其實對spark作業的性能的影響,是相當之高!!!經驗:在spark作業的運行過程中,只要一牽扯到有shuffle的操作,基本上shuffle操作的性能消耗,要占到整個spark作業的50%~90%。10%用來運行map等操作,90%耗費在shuffle操作。
spark操作調優(spark算子調優,比較重要):有些算子的性能,是比其他一些算子的性能要高的。foreachPartition替代foreach。
如果一旦遇到合適的情況,效果還是不錯的。
1、分配資源、并行度、RDD架構與緩存
2、shuffle調優
3、spark算子調優
4、JVM調優、廣播大變量。。。JVM調優原理概述。
JVM調優里面所有官方都推薦來降低cache操作占比
理論基礎:spark是用scala開發的。大家不要以為scala就跟java一點關系都沒有了,這是一個很常見的錯誤。spark的scala代碼調用了很多java api。scala也是運行在java虛擬機中的。spark是運行在java虛擬機中的。java虛擬機可能會產生什么樣的問題:內存不足??!!我們的RDD的緩存、task運行定義的算子函數,可能會創建很多對象。都可能會占用大量內存,沒搞好的話,可能導致JVM出問題。
堆內存:
存放我們創建的一些對象,堆內存分為年輕帶young generation和老年帶old generation,年輕帶內部又分為三塊,Eden區域比較大,兩個survivor區域比較小存活區域我們在spark task執行算子函數(我們自己寫的針對RDD的操作),可能會創建很多對象,這些對象,都是要放入JVM年輕代中的。每一次放對象的時候,都是放入eden區域,和其中一個survivor區域;另外一個survivor區域是空閑的。當eden區域和一個survivor區域放滿了以后(spark運行過程中,產生的對象實在太多了),就會觸發minor gc,小型垃圾回收。垃圾回收器gc會把不再使用的對象,從內存中清空,給后面新創建的對象騰出來點兒地方。
清理掉了不再使用的對象之后,那么也會將存活下來的對象(還要繼續使用的),放入之前空閑的那一個survivor區域中。這里可能會出現一個問題。默認eden、survior1和survivor2的內存占比是8:1:1。問題是,如果存活下來的對象是1.5,一個survivor區域放不下。此時就可能通過JVM的擔保機制(不同JVM版本可能對應的行為),將多余的對象,直接放入老年代了。
如果你的JVM內存不夠大的話,可能導致頻繁的年輕代內存滿溢,頻繁的進行minor gc。頻繁的minor gc會導致短時間內,有些存活的對象,多次垃圾回收都沒有回收掉。就是那些一直在用的又不能被釋放的就頻繁的倒來倒去!會導致這種短聲明周期(其實不一定是要長期使用的)對象,每回收一次,年齡長一歲!年齡過大,垃圾回收次數太多還沒有回收到,跑到老年代。
說白了就是短聲明周期對象卻跑到老年代里面去了!!!本來是短周期的,結果倒來倒去跑到老年代里面去了,理想情況下,老年代都是放一些生命周期很長的對象,數量應該是很少的。比如數據庫連接池,數據庫連接池本來就很少。
簡而言之,老年代中,可能會因為內存不足,囤積一大堆,短生命周期的,本來應該在年輕代中的,可能馬上就要被回收掉的對象。此時,可能導致老年代頻繁滿溢。頻繁進行full gc(全局/全面垃圾回收)。full gc就會去回收老年代中的對象。full gc由于這個算法的設計,是針對的是,老年代中的對象數量很少,滿溢進行full gc的頻率應該很少,因此采取了不太復雜,但是耗費性能和時間的垃圾回收算法。full gc很慢。
full gc / minor gc,無論是快,還是慢,都會導致jvm的工作線程停止工作,stop the world。簡而言之,就是說,gc的時候,spark停止工作了。等著垃圾回收結束。
內存不充足的時候,問題:
頻繁minor gc,也會導致頻繁spark停止工作;
老年代囤積大量活躍對象(短生命周期的對象),導致頻繁full gc,full gc時間很長,短則數十秒,長則數分鐘,甚至數小時。可能導致spark長時間停止工作;
嚴重影響咱們的spark的性能和運行的速度。
如何解決?
JVM調優的第一個點:降低cache操作的內存占比
spark中,堆內存又被劃分成了兩塊兒,一塊兒是專門用來給RDD的cache、persist操作進行RDD數據緩存用的;另外一塊兒,就是我們剛才所說的,用來給spark算子函數的運行使用的,存放函數中自己創建的對象。
默認情況下,給RDD cache操作的內存占比,是0.6,60%的內存都給了cache操作了。但是問題是,如果某些情況下,cache不是那么的緊張,問題在于task算子函數中創建的對象過多,然后內存又不太大,導致了頻繁的minor gc,甚至頻繁full gc,導致spark頻繁的停止工作。性能影響會很大。
針對上述這種情況,大家可以在spark uich查看。yarn去運行的話,那么就通過yarn的界面,去查看你的spark作業的運行統計,很簡單,大家一層一層點擊進去就好。可以看到每個stage的運行情況,包括每個task的運行時間、gc時間等等。如果發現gc太頻繁,時間太長。此時就可以適當調節這個比例。降低cache操作的內存占比,大不了用persist操作,選擇將一部分緩存的RDD數據寫入磁盤,或者序列化方式,配合Kryo序列化類,減少RDD緩存的內存占用;降低cache操作內存占比;對應的,算子函數的內存占比就提升了。這個時候,可能,就可以減少minor gc的頻率,同時減少full gc的頻率。對性能的提升是有一定的幫助的。一句話,讓task執行算子函數時,有更多的內存可以使用。
spark.storage.memoryFraction,0.6 -> 0.5 -> 0.4 -> 0.2
大家可以自己去調,然后觀察spark作業的運行統計!!!然后看看整體運行時間有沒有改善!gc是否頻繁,gc時間等!上述比例都可以調!根據不同需求來做!
.set("spark.storage.memoryFraction", "0.5")
看完上述內容,你們對spark-JVM的調優原理是什么有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。