Spark Executor 报错 java.lang.StackOverflowError

前两天,一个同事在Hue中查询Hive中的一个大表,运行一分钟左右就报错了:
  • Error while processing statement: FAILED: Execution Error, return code 3 from org.apache.hadoop.hive.ql.exec.spark.SparkTask
其执行的HQL语句也很简单,就是在一个大表上查询一些数据,加了一个where条件,将某一列值不为空的数据过滤出来,最后加个limit取其中200条数据。整个HQL的逻辑很简单,可是却不能获得正确结果。奇怪的是,若是只是把该HQL语句中的where过滤条件去掉以后,是能够查询到数据结果的,加了where就报错(这应该是因为没有where的时候与加上where过滤条件的执行过程不一致)。
因为, 生产环境中,使用的是Hive On Spak, 因此经过Yarn查看Spark任务的错误日志:

以及

Caused by: org.apache.hadoop.hive.ql.metadata.HiveException: Unable to rename output 
from: hdfs://nameservice1/tmp/hive/bdh_data/391198b6-8e23-4552-b34a-4925ee5c0760/hive_2017-06-20_18-26-46_451_3402833551811264654-2/-mr-10000/
.hive-staging_hive_2017-06-20_18-26-46_451_3402833551811264654-2/_task_tmp.-ext-10001/_tmp.000275_0 to: 
hdfs://nameservice1/tmp/hive/bdh_data/391198b6-8e23-4552-b34a-4925ee5c0760/hive_2017-06-20_18-26-46_451_3402833551811264654-2/-mr-10000/
.hive-staging_hive_2017-06-20_18-26-46_451_3402833551811264654-2/_tmp.-ext-10001/000275_0
刚开始我根据上面这一段错误信息去查找缘由及解决方法,在 这个页面 ( https://community.hortonworks.com/content/supportkb/49592/containers-logs-showing-tasks-that-are-unable-to-r.html ) 中查到了相似的错误及解决方法,按照这上面说的缘由是:因为在计算过程当中将存放临时数据的目录删除了,致使计算完了以后重命名文件时报错。所以,须要查namenode日志,找到是什么缘由致使目录被删除,并经过设置目录权限等方法来解决。
按照上面提供的思路去查找namenode日志,根本就没有找到上述目录的相关记录,并且在HDFS上检查对应的目录时,发现目录仍是存在的,只是该目录下是空的。另外也有人说,是由于多个任务对HDF中的同一个文件同时进行读写致使的,不过这些方法都没有解决个人问题。
因而,我尝试着根据下面这几行错误进行查找:
17/06/21 18:24:41 ERROR executor.Executor: Exception in task 275.3 in stage 0.0 (TID 278)
java.lang.StackOverflowErrorat java.util.concurrent.ConcurrentHashMap.hash(ConcurrentHashMap.java:333)at java.util.concurrent.ConcurrentHashMap.putIfAbsent(ConcurrentHashMap.java:1145)
at java.lang.ClassLoader.getClassLoadingLock(ClassLoader.java:464)
查阅了不少资料,有直接在Spark或者Hive项目中报Bug的,也有其它缘由的。后来,在下面三个链接中找到了一些眉目:
尤为是第一个里面的回答:

我尝试着去在spark-default.conf配置文件中添加(顺便也把GC回收的一些设置加上):
spark.executor.extraJavaOptions=“-Xss4096k-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintHeapAtGC -XX:+PrintGCApplicationConcurrentTime -Xloggc:gc.log"
觉得这样应该就能解决问题了,谁知另一些在使用spark的同事直接跟我说:spark-shell不能使用了。这挺奇怪的呀,我只是加了上面那一行设置,咋就不能正常执行了?我是我本身也进入spark-shell试试,果真直接报错了:

因而我根据终端的信息,找到了其中的一个Executor节点,进入到/opt/yarn/container-logs/目录下,也就是yarn存储container日志的目录,再根据container进入到对应目录下,查看stderr中记录的错误输出以下:

刚开始我觉得是由于我多加了一些GC设置致使的,因而我只保留了 -Xss4096k,改成:
spark.executor.extraJavaOptions=“-Xss4096k"
把其它设置都去除掉。再次进入Spark-shell,仍然包与以前同样的错误。我再次进入到container log目录下,查看stderr日志记录,此次报出来的是: Cann't find main class. 此次的错误更加奇葩了,一时之间毫无头绪。
后来,忽然想到,是否是不须要使用用双引号。因而我改为了:
spark.executor.extraJavaOptions=-Xss4096k
改完后,再次进入spark-shell,一切恢复了正常。
接着我进入hive shell,执行了以前的HQL语句,但是错误依然存在。经过Spark WEB界面,进入到Environment页面,查看任务的相关环境设置,发现:

说明我改的spark-default.conf对于hive没有生效。
经过查阅hive资料,了解到须要把相应的设置加入到hive-site.xml配置文件中,因而我在hive-site.xml中加入了:
<property>
<name>spark.executor.extraJavaOptions</name>
<value>-Xss4096k</value>
</property>
再次进入hive shell,从新执行以前的HQL语句,运行了一分钟左右,终于获得了期盼已久的结果!
具体缘由是: 因为Executor线程的栈满了,也就是函数调用层级过多致使,通常是递归调用的层级太多致使的。