Spark读取HDFS上的Snappy压缩文件所导致的内存溢出问题 java.lang.OutOfMemoryError: GC overhead limit exceeded
報(bào)錯java.lang.OutOfMemoryError: GC overhead limit exceeded
HDFS上有一些每天增長的文件,使用Snappy壓縮,突然某天OOM了
1.原因:
因?yàn)閟nappy不能split切片,也就會導(dǎo)致一個文件將會由一個task來讀取,讀取后解壓,數(shù)據(jù)又會膨脹好多倍,如果文件數(shù)太大而且你的并行度也挺大,就會導(dǎo)致大量full gc,最終OOM
為了程序能快速跑起來,只好將最后入HDFS前reparation(500),修改為1000,增加文件數(shù),減少每個文件數(shù)據(jù)量。
我自己的理解是如果HDFS上的Snappy壓縮文件需要Spark等計(jì)算框架取讀取并且需要切片,那么就要手動將文件大小控制在128MB附近,以使計(jì)算效率最大化,但是解壓后的數(shù)據(jù)仍然翻大約3倍
下面記錄一下,找問題,修復(fù)問題的過程,以及Spark參數(shù)調(diào)優(yōu)的過程,很漫長,太菜了。
HDFS上的文件
可以看到一個文件快700MB了,一共500個文件。
當(dāng)使用Spark讀取后做一系列計(jì)算就開始報(bào)錯OOM,用Jstat -gc pid 1000 查看gc情況,發(fā)現(xiàn)當(dāng)執(zhí)行到stage1的textFile讀取文件時就會卡住然后一直進(jìn)行full GC,最終OOM。
1.以為是數(shù)據(jù)傾斜,因?yàn)榭偸悄硞€stage某個task執(zhí)行時卡住
對數(shù)據(jù)進(jìn)行抽樣查看,發(fā)現(xiàn)并沒有數(shù)據(jù)傾斜,基本上沒有重復(fù)數(shù)據(jù)
rdd.sample(0.1,false).countByKey().forEach((k,v) ->System.out.println(k+"---"+v));2.可能內(nèi)存不夠用,或者參數(shù)調(diào)整的不對,開始調(diào)參
**方向:1.加內(nèi)存、2.堆外內(nèi)存、3.調(diào)JVM參數(shù)、4.調(diào)整緩存和執(zhí)行參數(shù)比例、5.增加核數(shù)增加并行度,減少每個task處理的數(shù)據(jù)量、6、調(diào)整代碼增加shuffer時的分區(qū)數(shù)、6.調(diào)整代碼先聚和之類的
因?yàn)榇a比較多,劃分的stage比較多,一時間通過WEB UI沒看出來是當(dāng)前stage中哪個算子出現(xiàn)的問題,一直以為是reduceBykey的時候報(bào)的錯,導(dǎo)致方向找錯了,所以怎么調(diào)整都是錯的
收獲就是對調(diào)參的了解更熟練了。
1.一開始就以為是執(zhí)行內(nèi)存不足所以我將fraction調(diào)為0.8,storageFraction調(diào)為0.2,不斷的增大執(zhí)行內(nèi)存,都無濟(jì)于事。
--conf spark.memory.fraction=0.8 --conf spark.memory.storageFraction=0.32.調(diào)整代碼提前過濾數(shù)據(jù)之類的全部嘗試了,沒用。
3.期間我修改了讀取文件時的分區(qū)數(shù)竟然沒想到是切片問題,發(fā)現(xiàn)不管怎么調(diào)整都只有500,當(dāng)時還在疑惑為啥啊,┭┮﹏┭┮
3.后來看WEB UI中task執(zhí)行情況,其實(shí)卡住的task一直在讀取數(shù)據(jù),input Size 項(xiàng)是在不斷增加的,下面是后來我修改后讀取的大小,一直讀到700MB,過程很慢,而且如果core數(shù)大也就是并行度大的話,我這里320個task并行度,每一個要讀取700MB,并且是需要解壓的,Snappy解壓后3G左右,查看task的errlog會發(fā)現(xiàn)日志出現(xiàn)具體我記不清了,大概就是讀取xxxx文件3G,通過內(nèi)存spill到了磁盤多少多少之類的,看到一個task讀了這么大,才忽然想起來snappy是不能split切片的
就會導(dǎo)致一個文件使用一個task讀取全部數(shù)據(jù)并解壓,最終OOM
也可能我當(dāng)時參數(shù)調(diào)整的不好,后面學(xué)習(xí)并總結(jié)了一下內(nèi)存調(diào)參,詳見:
https://blog.csdn.net/weixin_43736084/article/details/121541393
參數(shù)調(diào)整:
# --為了好看換行了 spark-submit --master spark://11.172.54.167:7077 --class $main --deploy-mode client --driver-memory 16g --executor-memory 25g --executor-cores 8 --total-executor-cores 320 --conf spark.memory.fraction=0.8 --conf spark.memory.storageFraction=0.3 --conf spark.memory.offHeap.enabled=true --conf spark.memory.offHeap.size=5g --conf "spark.executor.extraJavaOptions=-XX:+UseG1GC -XX:-TieredCompilation -XX:G1HeapRegionSize=16m -XX:InitiatingHeapOccupancyPercent=55 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:-UseCompressedClassPointers -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -XX:ReservedCodeCacheSize=512m -XX:+UseCodeCacheFlushing -XX:ParallelGCThreads=20 -XX:ConcGCThreads=20 -Xms20g -XX:+PrintGCDetails -XX:+PrintGCTimeStamps" --jars $jars xxxx.jar $date1 $max $date2 >> log/$log_file#代碼內(nèi)參數(shù) conf.set("spark.driver.maxResultSize", "8g"); conf.set("spark.serialize", "org.apache.spark.serializer.KryoSerializer"); conf.registerKryoClasses(new Class[]{ImmutableBytesWritable.class, HyperLogLog.class, HashSet.class, RegisterSet.class, IllegalArgumentException.class, FileCommitProtocol.TaskCommitMessage.class}); //conf.set("spark.kryo.registrationRequired","true"); #開啟的話類沒加到上面會報(bào)錯 conf.set("spark.kryoserializer.buffer.mb", "10"); conf.set("spark.shuffle.file.buffer", "128"); conf.set("spark.reducer.maxSizeInFlight", "144"); conf.set("spark.shuffle.io.maxRetries", "50"); conf.set("spark.shuffle.io.retryWait", "5s");總結(jié)
以上是生活随笔為你收集整理的Spark读取HDFS上的Snappy压缩文件所导致的内存溢出问题 java.lang.OutOfMemoryError: GC overhead limit exceeded的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 严重可丢命!夏季标配竟是"定时炸弹" 天
- 下一篇: linux设备驱动学习,linux设备驱