spark序列化异常和Executor的僵死问题

在Spark上执行hive语句的时候,出现类似于如下的异常:
  1. org.apache.spark.SparkDriverExecutionException: Execution error
  2.     at org.apache.spark.scheduler.DAGScheduler.handleTaskCompletion(DAGScheduler.scala:849)
  3.     at org.apache.spark.scheduler.DAGSchedulerEventProcessActor$anonfun$receive$2.applyOrElse(DAGScheduler.scala:1231)
  4.     at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498)
  5.     at akka.actor.ActorCell.invoke(ActorCell.scala:456)
  6.     at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237)
  7.     at akka.dispatch.Mailbox.run(Mailbox.scala:219)
  8.     at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)
  9.     at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
  10.     at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
  11.     at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
  12.     at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
  13. Caused by: java.lang.ClassCastException: scala.collection.mutable.HashSet cannot be cast to scala.collection.mutable.BitSet
  14.     at org.apache.spark.sql.execution.BroadcastNestedLoopJoin$anonfun$7.apply(joins.scala:336)
  15.     at org.apache.spark.rdd.RDD$anonfun$19.apply(RDD.scala:813)
  16.     at org.apache.spark.rdd.RDD$anonfun$19.apply(RDD.scala:810)
  17.     at org.apache.spark.scheduler.JobWaiter.taskSucceeded(JobWaiter.scala:56)
  18.     at org.apache.spark.scheduler.DAGScheduler.handleTaskCompletion(DAGScheduler.scala:845)
复制代码

排查其前后的日志,发现大都是序列化的东西:
  1. 14/08/13 11:10:01 INFO org.apache.spark.Logging$class.logInfo(Logging.scala:58): Serialized task 8.0:3 as 20849 bytes in 0 ms
  2. 14/08/13 11:10:01 INFO org.apache.spark.Logging$class.logInfo(Logging.scala:58): Finished TID 813 in 25 ms on sparktest0 (progress: 3/200)
复制代码

而在 spark-default.conf中,事先设置了序列化方式为Kryo:
  1. spark.serializer org.apache.spark.serializer.KryoSerializer
复制代码

根据异常信息,可见是HashSet转为BitSet类型转换失败,Kryo把松散的HashSet转换为了紧凑的BitSet,把序列化方式注释掉之后,任务可以正常执行。难道Spark的Kryo序列化做的还不到位? 此问题需要进一步跟踪。
9 Executor僵死问题
    运行一个Spark任务,发现其运行速度远远慢于执行同样SQL语句的Hive的执行,甚至出现了OOM的错误,最后卡住达几小时!并且Executor进程在疯狂GC。
    截取其一Task的OOM异常信息:
可以看到这是在序列化过程中发生的OOM。根据节点信息,找到对应的Executor进程,观察其Jstack信息:
  1. Thread 36169: (state = BLOCKED)
  2. - java.lang.Long.valueOf(long) @bci=27, line=557 (Compiled frame)
  3. - com.esotericsoftware.kryo.serializers.DefaultSerializers$LongSerializer.read(com.esotericsoftware.kryo.Kryo, com.esotericsoftware.kryo.io.Input, java.lang.Class) @bci=5, line=113 (Compiled frame)
  4. - com.esotericsoftware.kryo.serializers.DefaultSerializers$LongSerializer.read(com.esotericsoftware.kryo.Kryo, com.esotericsoftware.kryo.io.Input, java.lang.Class) @bci=4, line=103 (Compiled frame)
  5. - com.esotericsoftware.kryo.Kryo.readClassAndObject(com.esotericsoftware.kryo.io.Input) @bci=158, line=732 (Compiled frame)
  6. - com.esotericsoftware.kryo.serializers.DefaultArraySerializers$ObjectArraySerializer.read(com.esotericsoftware.kryo.Kryo, com.esotericsoftware.kryo.io.Input, java.lang.Class) @bci=158, line=338 (Compiled frame)
  7. - com.esotericsoftware.kryo.serializers.DefaultArraySerializers$ObjectArraySerializer.read(com.esotericsoftware.kryo.Kryo, com.esotericsoftware.kryo.io.Input, java.lang.Class) @bci=4, line=293 (Compiled frame)
  8. - com.esotericsoftware.kryo.Kryo.readObject(com.esotericsoftware.kryo.io.Input, java.lang.Class, com.esotericsoftware.kryo.Serializer) @bci=136, line=651 (Compiled frame)
  9. - com.esotericsoftware.kryo.serializers.FieldSerializer$ObjectField.read(com.esotericsoftware.kryo.io.Input, java.lang.Object) @bci=143, line=605 (Compiled frame)
  10. - com.esotericsoftware.kryo.serializers.FieldSerializer.read(com.esotericsoftware.kryo.Kryo, com.esotericsoftware.kryo.io.Input, java.lang.Class) @bci=44, line=221 (Compiled frame)
  11. - com.esotericsoftware.kryo.Kryo.readObject(com.esotericsoftware.kryo.io.Input, java.lang.Class, com.esotericsoftware.kryo.Serializer) @bci=136, line=651 (Compiled frame)
  12. - com.esotericsoftware.kryo.serializers.FieldSerializer$ObjectField.read(com.esotericsoftware.kryo.io.Input, java.lang.Object) @bci=143, line=605 (Compiled frame)
  13. - com.esotericsoftware.kryo.serializers.FieldSerializer.read(com.esotericsoftware.kryo.Kryo, com.esotericsoftware.kryo.io.Input, java.lang.Class) @bci=44, line=221 (Compiled frame)
  14. - com.esotericsoftware.kryo.Kryo.readClassAndObject(com.esotericsoftware.kryo.io.Input) @bci=158, line=732 (Compiled frame)
  15. - org.apache.spark.serializer.KryoDeserializationStream.readObject(scala.reflect.ClassTag) @bci=8, line=118 (Compiled frame)
  16. - org.apache.spark.serializer.DeserializationStream$anon$1.getNext() @bci=10, line=125 (Compiled frame)
  17. - org.apache.spark.util.NextIterator.hasNext() @bci=16, line=71 (Compiled frame)
  18. - org.apache.spark.storage.BlockManager$LazyProxyIterator$1.hasNext() @bci=4, line=1031 (Compiled frame)
  19. - scala.collection.Iterator$anon$13.hasNext() @bci=4, line=371 (Compiled frame)
  20. - org.apache.spark.util.CompletionIterator.hasNext() @bci=4, line=30 (Compiled frame)
  21. - org.apache.spark.InterruptibleIterator.hasNext() @bci=22, line=39 (Compiled frame)
  22. - scala.collection.Iterator$anon$11.hasNext() @bci=4, line=327 (Compiled frame)
  23. - org.apache.spark.sql.execution.HashJoin$anonfun$execute$1.apply(scala.collection.Iterator, scala.collection.Iterator) @bci=14, line=77 (Compiled frame)
  24. - org.apache.spark.sql.execution.HashJoin$anonfun$execute$1.apply(java.lang.Object, java.lang.Object) @bci=9, line=71 (Interpreted frame)
  25. - org.apache.spark.rdd.ZippedPartitionsRDD2.compute(org.apache.spark.Partition, org.apache.spark.TaskContext) @bci=48, line=87 (Interpreted frame)
  26. - org.apache.spark.rdd.RDD.computeOrReadCheckpoint(org.apache.spark.Partition, org.apache.spark.TaskContext) @bci=26, line=262 (Interpreted frame)
复制代码

有大量的 BLOCKED线程,继续观察GC信息,发现大量的 FULL GC。
    分析,在插入Hive表的时候,实际上需要写HDFS,在此过程的HashJoin时,伴随着大量的Shuffle写操作,JVM的新生代不断GC,Eden Space写满了就往Survivor Space写,同时超过一定大小的数据会直接写到老生代,当新生代写满了之后,也会把老的数据搞到老生代,如果老生代空间不足了,就触发FULL GC,还是空间不够,那就OOM错误了,此时线程被Blocked,导致整个Executor处理数据的进程被卡住。
当处理大数据的时候,如果 JVM配置不当就容易引起上述问题。解决的方法就是增大Executor的使用内存,合理配置新生代和老生代的大小,可以将老生代的空间适当的调大点
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值