1. 程式人生 > >spark JVM調優之原理概述以及降低cache操作的記憶體佔比

spark JVM調優之原理概述以及降低cache操作的記憶體佔比

每一次放物件的時候,都是放入eden區域,和其中一個survivor區域;另外一個survivor區域是空閒的。


當eden區域和一個survivor區域放滿了以後(spark執行過程中,產生的物件實在太多了),就會觸發minor 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停止工作了。等著垃圾回收結束。


記憶體不充足的時候,問題:
1、頻繁minor gc,也會導致頻繁spark停止工作
2、老年代囤積大量活躍物件(短生命週期的物件),導致頻繁full gc,full gc時間很長,短則數十秒,長則數分鐘,甚至數小時。可能導致spark長時間停止工作。
3、嚴重影響咱們的spark的效能和執行的速度。


JVM調優的第一個點:降低cache操作的記憶體佔比:

spark中,堆記憶體又被劃分成了兩塊兒,一塊兒是專門用來給RDD的cache、persist操作進行RDD資料快取用的;另外一塊兒,就是我們剛才所說的,用來給spark運算元函式的執行使用的,存放函式中自己建立的物件。

預設情況下,給RDD cache操作的記憶體佔比,是0.6,60%的記憶體都給了cache操作了。但是問題是,如果某些情況下,cache不是那麼的緊張,問題在於task運算元函式中建立的物件過多,然後記憶體又不太大,導致了頻繁的minor gc,甚至頻繁full gc,導致spark頻繁的停止工作。效能影響會很大。

針對上述這種情況,可以在spark ui。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