症状
spark streaming driver内存一直增长,直到小心脏受不了,凝固在那里不死但是动不了内存爆满。块丢失
环境
amabri hdp 2.3
spark 1.4.1
hadoop/yarn 2.7
yarn-client模式,两个excutor
分析
分析streaming日志:
WARN TaskSetManager: Lost task 3.1 in stage 426996.0 (TID 7643834, bigdata4): java.lang.Exception: Could not compute split, block input-0-1453614402000 not found
at org.apache.spark.rdd.BlockRDD.compute(BlockRDD.scala:51)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:244)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:35)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:244)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:35)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:244)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:35)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:244)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:35)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:244)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:35)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:244)
at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:70)
at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:41)
at org.apache.spark.scheduler.Task.run(Task.scala:70)
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:213)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
- 块丢失,最头疼的问题,日志一直打印这个日志,一直到excutor全部挂掉,driver内存暴高假死,
- 原因是由于 spark streaming driver 被沾满的瞬间不能通信一起的数据不能读取最终的异常就是块丢失。我花费了好几天时间得到这句话。
- 那就制造重现吧, 等重现以后使用jmap -dump:format=b,file=10307.hprof 10307 dump日志
- 使用工具进行分析
- 使用工具也有讲究的: eclipse的 MAT 、ibm的也有个、jvm visualStudio也可以打开,推荐使用Eclipse Memory Analyzer MAT ,直接查看分析leak结果,发现YarnHistoryService占用81.49%.
看图,看图:
内存分析dashboard:
driver_mem_heigh
类详情图:
driver_mem_heigh_detail - 那就分析下YarnHistoryService这玩意是做什么的吧,找了半天找不到源码,看堆栈信息发现他里边有个queue那就是了,和名字猜想,他肯定记录了一些日志信息在队列里,没有被清理。导致内存泄露。
- 找到配置的地方。因为我使用Ambari HDP就在spark的配置中查找,找到了这个配置在
Advanced spark-defaults->spark.yarn.services 这个配置项中。我想清空他,但是好像是必填的。 - 没办法只能去linux上直接修改他的配置文件了,登录你的spark driver所在的机器。 版本路径可能需要修改
vi /etc/spark/2.3.2.0-2950/0/spark-defaults.conf
#注释掉下面四个配置项:
#spark.history.provider org.apache.spark.deploy.yarn.history.YarnHistoryProvider
#spark.history.ui.port 18080
#spark.yarn.historyServer.address bigdata3:18080
#spark.yarn.services org.apache.spark.deploy.yarn.history.YarnHistoryService
然后再启动你的spark。
9. 观察一段时间以后,好了一切正常了,世界和平。
结论
dirver的内存泄露,是由于spark yarn 的配置不当引起,也可能是spark的bug。
刚开始不知道块丢失一般是怎么回事,就各种彷徨,自己分析可以得出结论,块丢失一般有几种可能:
1.spark的ttl机制导致数据丢失。
2.入库效率低导致数据累积,导致内存问题。
3.还是内存问题:内存爆满,有可能在driver上,也可能在excutor上。
4.yarn kill掉了某个excutor。
建议
问题之外建议。
1. 压缩方式使用 sparkConf.set(“spark.serializer”, “org.apache.spark.serializer.KryoSerializer”)
2. 修改yarn/spark的GC机制为CMS(可行)或者G1(作者未验证) 参考http://www.youkuaiyun.com/article/2015-06-02/2824823