一开始使用yarn-client模式提交作业时一切正常,但换成cluster模式下
使用sparksql方法执行hive查询语句时,却出现了如下的OOM问题:
Exception in thread "Thread-3" java.lang.OutOfMemoryError: PermGen space
出现这个错误原主要原因是太多的类或者太大的类都被加载到永久代,导致存储器中永久代的内存耗尽。而我们这里主要是因为SparkSql在获取Hive元数据信息、SQL解析等进行序列化反序列化过程中中间可能产生较多的class文件。
解决方法就是增加对Driver的JVM配置,因为Driver才负责SQL的解析和元数据获取。例如在提交作业时:
--conf "spark.driver.extraJavaOptions=-XX:PermSize=128M -XX:MaxPermSize=256M"
但是为什么在yarn-client模式运行时是正常的呢,网上查了下,原来在*$SPARK_HOME/bin/spark-class*文件中已经设置了永久代大小:
JAVA_OPTS="-XX:MaxPermSize=256m $OUR_JAVA_OPTS"
当以yarn-client模式运行时,driver就运行在客户端的spark-submit进程中,其JVM参数是取的spark-class文件中的设置,所以没有出现永久代溢出现象。
总结一下Spark中各个角色的JVM参数设置:
- Driver的JVM参数:
-Xmx,-Xms,如果是yarn-client模式,则默认读取spark-env文件中的SPARK_DRIVER_MEMORY值,-Xmx,-Xms值一样大小;如果是yarn-cluster模式,则读取的是spark-default.conf文件中的spark.driver.extraJavaOptions对应的JVM参数值。
PermSize,如果是yarn-client模式,则是默认读取spark-class文件中的JAVA_OPTS="-XX:MaxPermSize=256m $OUR_JAVA_OPTS"值;如果是yarn-cluster模式,读取的是spark-default.conf文件中的spark.driver.extraJavaOptions对应的JVM参数值。
GC方式,如果是yarn-client模式,默认读取的是spark-class文件中的JAVA_OPTS;如果是yarn-cluster模式,则读取的是spark-default.conf文件中的spark.driver.extraJavaOptions对应的参数值。
以上值最后均可被spark-submit工具中的–driver-java-options参数覆盖。
- Executor的JVM参数:
-Xmx,-Xms,如果是yarn-client模式,则默认读取spark-env文件中的SPARK_EXECUTOR_MEMORY值,-Xmx,-Xms值一样大小;如果是yarn-cluster模式,则读取的是spark-default.conf文件中的spark.executor.extraJavaOptions对应的JVM参数值。
PermSize,两种模式都是读取的是spark-default.conf文件中的spark.executor.extraJavaOptions对应的JVM参数值。
GC方式,两种模式都是读取的是spark-default.conf文件中的spark.executor.extraJavaOptions对应的JVM参数值。
- Executor数目及所占CPU个数
如果是yarn-client模式,Executor数目由spark-env中的SPARK_EXECUTOR_INSTANCES指定,每个实例的数目由SPARK_EXECUTOR_CORES指定;如果是yarn-cluster模式,Executor的数目由spark-submit工具的–num-executors参数指定,默认是2个实例,而每个Executor使用的CPU数目由–executor-cores指定,默认为1核。
每个Executor运行时的信息可以通过yarn logs命令查看到,类似于如下:
14/08/13 18:12:59 INFO org.apache.spark.Logging$class.logInfo(Logging.scala:58): Setting up executor with commands: List($JAVA_HOME/bin/java, -server, -XX:OnOutOfMemoryError='kill %p', -Xms1024m -Xmx1024m , -XX:PermSize=256M -XX:MaxPermSize=256M -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:/tmp/spark_gc.log, -Djava.io.tmpdir=$PWD/tmp, -Dlog4j.configuration=log4j-spark-container.properties, org.apache.spark.executor.CoarseGrainedExecutorBackend, akka.tcp://spark@sparktest1:41606/user/CoarseGrainedScheduler, 1, sparktest2, 3, 1>, <LOG_DIR>/stdout, 2>, <LOG_DIR>/stderr)
其中,akka.tcp://spark@sparktest1:41606/user/CoarseGrainedScheduler表示当前的Executor进程所在节点,后面的1表示Executor编号,sparktest2表示ApplicationMaster的host,接着的3表示当前Executor所占用的CPU数目。
参考来源:
jvm - Spark Sql is throwing PermGen Space Error - Stack Overflow