spark streaming 排错--JVM方法栈溢出

在流式计算过程中,会遇到格式各样的问题。最常见的就是内存溢出,内存溢出又分为两类:堆溢出,栈溢出。

对于堆溢出要分两种情况:

      1.突然堆溢出,这种情况的处理方案参照spark core对于堆溢出的处理,不做详述。

      2.渐进式堆溢出,这种情况有好几种

然而对于栈的溢出,也和以上类似,今天不说堆的溢出,专门讲解栈的溢出。

1. 渐进式方法栈溢出

       这种方式的方法栈溢出最不好排查,也不能通过日志的方式来检查,因为日志中只会告诉你栈溢出。这个只能通过反复复核逻辑代码,检查不和规范的地方。

       我们在开发流式任务时,就遇到一个非常变态的方法栈溢出,最终排查了很久才找到原因。引起方法栈的原因是这样的:在开发过程中,上一个batch的数据需要在下一个batch中继续使用。因为数据量比较少,其次为了减少对其他架构的依赖。在stream.transform算子中持久化(persist/cache)完数据,就把数据注册成Spark sql表,并且关闭了数据清理(spark.streaming.unpersist=false)。流式计算开发完成后就部署到集群上,前几个小时没有问题。等过了一晚上之后发现batch的时间长度被拉的特别的长,并且时随着时间推移batch被越拉越长。亮点是流式计算输出的数据没有问题,各种数据指标正常且流式计算产出的数据也正常,但是就是sparkUI对于一个batch的时间越拉越越。

spark streaming 排错--JVM方法栈溢出_第1张图片

      出现这个问题,曾今一度怀疑是不是sparkUI出现了bug。因为数据产出正常,所以没有停下手中的其他任务找一下原因并修复。但是到第二天的下午,流式任务就终止了,错误提示是栈溢出。这样才意识到问题的严重性,第一步先排查整个项目是否有递归计算。排查过后,整个计算任务压根没有递归计算和大量压栈操作。没有递归计算,却出现了方法栈溢出简直不可思议。于是准备增加JVM方法栈的深度,并且提高非堆空间(spark.driver.memoryOverhead)的比例。重新部署后,这个问题依然没有解决。在重新审查sparkUI时发现一个奇怪的现象:后期的每一个batch会skip大量的stage,这些跳过的都是前几个batch所执行的stage。看到这终于找到方法栈溢出的原因,因为spark会递归所有依赖关系,当前batch使用上一个batch的计算结果(spark sql table),在使用过程中在上一个batch仅仅只是cache/persist,整个依赖关系并没有切断。所以导致整个依赖栈越来越长,直到方法栈溢出。后来修改了一下每个batch结束后,需要缓存的DataFrame做一次checkpoint用来切断整个依赖关系,这样就恢复了正常。由于checkpoint需要hdfs磁盘IO,所以对流式计算有一定的性能影响,后来修改成每隔5-6个batch执行一次checkpoint。最终问题得以解决。

【未完】

你可能感兴趣的:(spark streaming 排错--JVM方法栈溢出)