你在工作當中有遇到內存溢出問題嗎?你是如何解決的?
oom通常出現在execution內存中,因為storage這塊內存在放滿之後,會直接丟棄內存中舊的數據,對性能有點影響但不會導致oom。
一 OOM原因
driver端生成大對象
collect數據收集導致
map 類操作產生大量數據包括 map,flatMap,filter,mapPartitions 等
shuffle 後產生數據傾斜
二 Driver 內存不足
1.用戶在Dirver端生成大對象,比如創建了一個大的集合數據結構
--driver-memory MEM Memory for driver (e.g. 1000M, 2G) (Default: 1024M).
2.collect
本身不建議將大的數據從executor端,collect回來。建議將driver端對collect回來的數據所作的操作,轉換成executor端rdd操作
若無法避免,估算collect需要的內存,相應增加driver-memory的值
rdd = sc.parallelize(range(100))rdd.flatMap(lambda x: [&39;%x*50 for _ in range(100000)]).collect() 39;%d& 分區輸出
三 Executor 內存不足
1.增加 Executor 內存
--executor-memory MEM Memory per executor (e.g. 1000M, 2G) (Default: 1G).
2.map過程產生大量對象導致內存溢出
這種溢出的原因是在單個map中產生了大量的對象導致的,例如:rdd.map(x=>for(i <- 1 to 10000) yield i.toString),這個操作在rdd中,每個對象都產生了10000個對象,這肯定很容易產生內存溢出的問題。針對這種問題,在不增加內存的情況下,可以通過減少每個Task的大小,以便達到每個Task即使產生大量的對象Executor的內存也能夠裝得下。具體做法可以在會產生大量對象的map操作之前調用repartition方法,分區成更小的塊傳入map。例如:rdd.repartition(10000).map(x=>for(i <- 1 to 10000) yield i.toString)。
3.數據傾斜導致內存溢出
解決方案:Spark數據傾斜解決方案
4.coalesce調用導致內存溢出
因為hdfs中不適合存小問題,所以Spark計算後如果產生的文件太小,我們會調用coalesce合併文件再存入hdfs中。但是這會導致一個問題,例如在coalesce之前有100個文件,這也意味著能夠有100個Task,現在調用coalesce(10),最後只產生10個文件,因為coalesce並不是shuffle操作,這意味著coalesce並不是按照我原本想的那樣先執行100個Task,再將Task的執行結果合併成10個,而是從頭到位只有10個Task在執行,原本100個文件是分開執行的,現在每個Task同時一次讀取10個文件,使用的內存是原來的10倍,這導致了OOM。解決這個問題的方法是令程序按照我們想的先執行100個Task再將結果合併成10個文件,這個問題同樣可以通過repartition解決,調用repartition(10),因為這就有一個shuffle的過程,shuffle前後是兩個Stage,一個100個分區,一個是10個分區,就能按照我們的想法執行。
5.shuffle後內存溢出
shuffle內存溢出的情況可以說都是shuffle後,單個文件過大導致的。在Spark中,join,reduceByKey這一類型的過程,都會有shuffle的過程,在shuffle的使用,需要傳入一個partitioner,大部分Spark中的shuffle操作,默認的partitioner都是HashPatitioner,默認值是父RDD中最大的分區數,這個參數通過spark.default.parallelism控制(在spark-sql中用spark.sql.shuffle.partitions) , spark.default.parallelism參數只對HashPartitioner有效,所以如果是別的Partitioner或者自己實現的Partitioner就不能使用spark.default.parallelism這個參數來控制shuffle的並發量了。如果是別的partitioner導致的shuffle內存溢出,就需要從partitioner的代碼增加partitions的數量。
6.standalone 模式資源分配不均
在standalone的模式下如果配置了--total-executor-cores 和 --executor-memory 這兩個參數,但是沒有配置--executor-cores這個參數的話,就有可能導致,每個Executor的memory是一樣的,但是cores的數量不同,那麼在cores數量多的Executor中,由於能夠同時執行多個Task,就容易導致內存溢出的情況。這種情況的解決方法就是同時配置--executor-cores或者spark.executor.cores參數,確保Executor資源分配均勻。
7.在RDD中,共用對象能夠減少OOM的情況
rdd.flatMap(x=>for(i <- 1 to 1000) yield (&34;,&34;))導致OOM,但是在同樣的情況下,使用rdd.flatMap(x=>for(i <- 1 to 1000) yield &34;+&34;)就不會有OOM的問題,
這是因為每次(&34;,&34;)都產生一個Tuple對象,
而&34;+&34;,不管多少個,都只有一string個對象,指向常量池。