本文介绍Spark作业异常的排查方法和解决方案。
内存问题引起的报错
Container killed by YARN for exceeding memory limits
报错原因:提交App时申请的内存量较低,但JVM启动占用了更多的内存,超过了自身的申请量,导致被YARN NodeManager异常终止。特别是Spark类型作业,可能会占用多的堆外内存,很容易被异常终止。
解决方案:在EMR控制台中Spark服务的配置页面,调大spark.driver.memoryOverhead或spark.executor.memoryOverhead的值。
Spark任务读写OSS文件时出现Container killed by YARN for exceeding memory limits
报错原因:可能是由于读写OSS时使用的内存缓存过大。
解决方案:增大Spark Executor内存。如果无法增大Spark Executor内存,可以在EMR控制台Hadoop-Common服务配置页面的core-site.xml页签下,调整以下和OSS相关的配置参数:
fs.oss.read.readahead.buffer.count:0
fs.oss.read.buffer.size:16384
fs.oss.write.buffer.size:16384
fs.oss.memory.buffer.size.max.mb:512
Error: Java heap space
报错原因:Spark作业Task处理的数据量较大,但Executor JVM申请的内存量不足,从而出现java.lang.OutOfMemoryError报错。
解决方案:在EMR控制台中Spark服务的配置页面,针对不同的场景调大spark.executor.memory或spark.driver.memory的值。
读取Snappy文件时报错OutOfMemoryError
针对Spark作业,您可以在EMR控制台中Spark服务配置页面的spark-defaults.conf页签下,新增spark.hadoop.io.compression.codec.snappy.native=true配置。
其他Spark Driver OOM内存不足场景
您可以按照以下方案解决:
在EMR控制台中Spark服务的配置页面,调大spark.driver.memory的值。
查看是否有collect等把数据拉取到driver的操作,如果collect的数据比较大,建议使用foreachPartitions在executor进行操作,移出collect相关代码。
设置spark.sql.autoBroadcastJoinThreshold=-1。
其他Spark Executor OOM内存不足场景
您可以按照以下方案解决:
在EMR控制台中Spark服务的配置页面,调大spark.executor.memory的值。
调小spark.executor.cores的值。
调大spark.default.parallelism及spark.sql.shuffle.partitions的值。
文件格式报错
Hive或Impala作业读取Spark导入的Parquet表报错
具体报错:
Failed with exception java.io.IOException:org.apache.parquet.io.ParquetDecodingException: Can not read value at 0 in block -1 in file xxx
报错原因:由于Hive和Spark在Decimal类型上使用了不同的转换方式写入Parquet,导致Hive无法正确读取Spark导入的数据。
解决方案:已使用Spark导入的数据,如果需要被Hive或Impala使用,建议在EMR控制台中Spark服务配置页面的spark-defaults.conf页签下,增加spark.sql.parquet.writeLegacyFormat=true配置后重新导入数据。
Shuffle报错
java.lang.IllegalArgumentException: Size exceeds Integer.MAX_VALUE
报错原因:在Spark Shuffle时,Partition数量过少使得Block Size超过Integer.MAX_VALUE的值。
解决方案:建议增加Partition个数,在控制台中调大spark.default.parallelism和spark.sql.shuffle.partitions的值,或者在Shuffle前执行Repartition。
外部数据源问题引起的报错
java.sql.SQLException: No suitable driver found for jdbc:mysql:xxx
mysql-connector-java版本过低,请替换为较新版本(例如5.1.48以上版本)。
连接RDS报错Invalid authorization specification, message from server: ip not in whitelist
检查RDS的白名单设置,将EMR集群节点(需要包括master、core、task等节点组)的内网地址添加到RDS的白名单中。
其他异常报错
Spark UI中一直没有分配Job,或者Job全部结束,但是Spark任务长时间不结束
进入Spark UI,查看Executor页面,分析driver的thread dump。如果很多orc相关的线程,则在Spark任务启动前设置--conf spark.hadoop.hive.exec.orc.split.strategy=BI,再重新启动Spark任务。如果是Spark2.x版本,还需要查看spark.sql.adaptive.enabled是否为true,如果为true,需要修改为false。
Spark任务一直不结束,同时无法进入Spark UI
报错原因:通常是driver内存不足,fullgc严重导致的。
解决方案:增大spark.driver.memory的值。
Spark使用代码读取Hive数据时,出现NoSuchDatabaseException: Database 'xxx' not found
查看初始化SparkSession的时候,是否执行了
.enableHiveSupport()
。如果没有执行,则需要手动执行。查看是否有代码执行了
new SparkContext()
。如果有则移出相关代码,从SparkSession中获取SparkContext。
Spark作业出现java.lang.ClassNotFoundException
根据Class的信息找到对应的JAR包,并通过以下方案处理:
方案1:提交Spark任务时,使用
--jars
把JAR包提交上去。方案2:使用spark.driver.extraclasspath和spark.executor.extraclasspath把JAR包的路径写入classpath,这个方案需要EMR集群每个节点上都有对应的JAR包。