Spark FAQ

本文汇总了使用DLA Spark的常见问题及解决方案。

常见问题

常见问题

如何处理Spark作业报错:The VirtualCluster's name is invalid or the VirtualCluster's is not in running state?

常见原因:虚拟集群名称(VcName)没配置,一般是由于该虚拟集群不存在或者该虚拟集群不是在运行中状态

解决方案:您需要填写正确的虚拟集群,如下所示。

  • 如果该错误是DLA控制台作业管理界面报出,请先创建虚拟集群,再提交作业。

  • 如果您使用的不是控制台方式,而是Aliyun OpenAPI、Spark-submit脚本或者Jupyter等,需要检查配置参数VcName对应的需求集群是否未填写或者填写错误。查找可用的虚拟集群名称的方法如下。

  1. 登录DLA控制台

  2. 左侧导航栏单击虚拟集群管理

  3. 在虚拟集群列表中选择状态是运行中的虚拟集群的名字。

如何处理Spark作业报错:User %s do not have right permission [ *** ] to resource [ *** ]?

常见原因:当前子账号没有调用该接口的权限。

解决方案如下。

如何处理Spark作业报错:No space left on device?

首先判断报错信息是否是Executor本地内存不足导致的,判断方法是查看SparkUI中Executor的Stderr日志信息。如果是,您可以通过添加如下配置来增加Executor本地盘的大小。

spark.k8s.shuffleVolume.enable: true
spark.dla.local.disk.size:  50Gi
注意
  • 本地盘为ESSD类型,暂时免费,后续会收费。

  • 当前本地盘最大为100Gi。

  • 如果已经配置了100Gi的本地盘,仍然提示空间不足,那么可以考虑增加Executor的数量。

Spark Executor出现Dead怎么处理?

首先进入SparkUI页面,如果Failed Stages的Failure reason中包含Failed to connect to /xx.xx.xx.xx:xxxx或者在SparkUI->Executors页面出现状态为Dead的Executor,往往是因为Spark Executor由于某种原因退出了。

说明

如何进入SparkUI页面,详情请参见Spark UI

常见场景如下。

  1. Driver日志出现如下报错:ERROR TaskSchedulerImpl: Lost executor xx on xx.xx.xx.xx:The executor with id xx exited with exit code 137.

原因:Executor进程内存用超了。容器的整体内存使用超过了容器最大允许使用内存上限,导致Spark进程被kill-9强制杀掉了。Spark Executor除了JVM本身使用内存外,往往还包括堆外内存(Shuffle、Cache),以及Python UDF等使用的内存。

解决方案:调大参数spark.executor.memoryOverhead(单位MB)。该参数表示容器内部非Spark Executor进程可使用的内存容量,默认是Executor容器总内存容量的30%。比如您当前配置的Executor规格是Medium(2C8G),那么默认的MemoryOverhead是2.4G,您可以调大该配置如下:

spark.executor.memoryOverhead = 4000。

2.日志中出现java.lang.OutOfMemoryError的日志。

原因:在SparkUI->Executors页面查看状态为Dead的Executor的stderr/stdout日志链接查找具体报错原因。

解决方案如下。

  • 优化应用,避免大内存占用。

  • 调大Executor资源规格,比如Small提高到Medium。

3.除上述报错以外,其他报错的解决方案。

查看Dead状态的Executor日志,如果报错位置位于用户业务代码,需要业务开发解决。其他错误信息您可以在搜索引擎中搜索相关报错信息。

Spark访问数据源网络不通怎么办?

默认情况下,DLA Spark不能访问用户VPC,只能访问OSS、Tablestore、MaxCompute等服务型数据源,并且不能访问公网。

DLA Spark可以通过挂载用户VPC网卡的方式来访问用户VPC中的数据源,以及访问公网。挂载用户网卡后,网络模型与一台普通用户VPC的ECS完全一样,可以复用阿里云VPC网络产品的所有功能,包括内网、公网、专线等等。如何挂载用户网卡,详情请参见文档配置数据源网络

如何处理Spark作业日志中报错:ClassNotFound?

常见原因:一般是由于缺少类导致。您可以通过打开所上传的JAR包(jar tvf xxx.jar | grep xxxx),确认该类是否存在。

解决方案如下。

  • 如果是用户业务相关的类,需要重新打包,确保目标类被打进去。

  • 如果是第三方包,您可以采用如下方式。

  1. 使用Maven的Shade或者Assembly插件,加入依赖包(Shade和Assembly可以自行查找Maven相关资料)。

  2. 使用作业配置指南中“jars”参数将第三方JAR包单独上传。

如何处理Spark作业日志中报错:NoSuchMethod?

常见原因:出现了JAR包冲突,可能是引入了跟Spark冲突的第三方包导致。

解决方案:您可以通过Provided、Relocation等Maven常见的冲突解决方式来解决,相关技术属于通用技术,您可以进行搜索或者参考dla spark demo项目进行Maven Pom配置。

为什么Spark SQL作业使用show tables或者show database查询发现显示的列表不足?

首先请确认是否使用了DLA的元数据服务。

  • 如果您使用的是DLA的元数据服务,需要确认权限问题。您只能看到自己具有权限的库表,其他库表隐藏。

  • 如果您使用的不是DLA的元数据服务,需要确认自建元数据服务的权限和连通的正确性。

为什么在DLA SQL中执行select * from db1.table1成功, 但在Spark中报错?

详细报错如下。

java.lang.NullPointerException
 at java.net.URI$Parser.parse(URI.java:3042)
 at java.net.URI.<init>(URI.java:588)
 at org.apache.spark.sql.hive.client.JianghuClientImpl$$anonfun$getTableOption

常见原因如下。

  • 表的存储格式不对,目前只支持OSS和HDFS。

  • 表名中出现了中划线-,中划线为Spark SQL保留字,不允许在表名中使用。

为什么在DLA SQL中执行select * from db1.table1有数据,但在Spark中没有?

常见原因如下。

  • 表中对应的OSS或者HDFS地址有嵌套关系。例如您指定的LOCATION为oss://db/table/, 指定了partiion1和parition2,则您的数据文件应当类似oss//db/table/partition1=a/partiion2=b/data.csv。DLA SQL支持多层嵌套目录oss//db/table/partition1=a/partiion2=b/extral_folder/data.csv,但Spark SQL暂不支持。

  • DLA SQL的语法和Spark SQL的语法略有区别,如何调试SQL,请参见Spark SQL

为什么Spark作业提示错误日志oss object 403?

常见原因如下。

  • DLA Spark不支持跨Region读JAR包或者读文件。

  • 通过参数spark.dla.rolearn指定的Role没有读取这个OSS路径的权限。

  • 文件地址填写错误。

  • 文件与文件之间没有用逗号隔开或者写成JSON的List。

如何处理Spark SQL读JSON外表(包含日志投递自建)时的报错ClassNotFoundException: org.apache.hadoop.hive.serde2.JsonSerDe?

解决方案具体步骤如下。

  1. 下载https://repo1.maven.org/maven2/org/apache/hive/hive-serde/3.1.2/hive-serde-3.1.2.jar上传至OSS。

  2. 在Spark SQL开头添加语句add jar oss://path/to/hive-serde-3.1.2.jar;

如何处理执行Spark SQL报错:Exception in thread "main" java.io.IOException: No FileSystem for scheme: oss?

解决方案:您可以在Spark SQL中添加如下命令。

set spark.dla.connectors=oss;

作业慢如何排查?

常见的作业执行慢可以分为两大类:

  • 作业异常导致,您可以通过下面方法1和方法2排查。

  • 作业无异常仍然很慢,您可以通过方法3、方法4和方法5排查。

1. 查看是否有Executor状态是Dead。

查看方式:单击展开对应作业的操作列表,点击SparkUI进入Spark页面,切换到Executors页面,查看Status字段。

解决方案:具体解决办法请参见Spark Executor出现Dead怎么处理

2. 查看Driver日志,是否有异常信息导致Task终止并重试。

查看方式:单击展开对应作业的操作列表,点击SparkUI进入Spark页面,切换到Executors页面,找到Executor ID字段中为driver的stderr日志。

解决方案:通过报错信息查看异常的具体原因,大部分跟业务逻辑相关,您可以对其进行排查或者通过搜索引擎搜索解决。

注意

如果是OOM异常则需要检查业务逻辑是否有大内存占用,特别是某个字段特别大的情况,如果确实需要更大内存,您可以考虑使用更大规格的Executor或Driver节点。

3. 查看是否由资源不足导致。

查看方法:单击展开对应作业的操作列表,点击SparkUI进入Spark页面,切换到Stages页面,从Stage列表中,找到执行比较慢的一些Stage,查看这些Stage的并发度(Tasks: Succeeded/Total)。

如果Stage的Total比(Executor数目)*(Executor cores)多,那么就确认存在资源不足。

比如某个Stage Tasks Total是100,spark.executor.instances=5,spark.executor.resourceSpec=medium(2C8G),那么每一轮Tasks只能跑10个,需要跑10轮。

此时需要增加作业的资源总量,调大spark.executor.instances参数,或者调大Executor规格(spark.executor.resourceSpec)。最好不要超过同时运行的Stage的Tasks总数,否则会导致资源浪费。

4. 查看是否由GC导致。

查看方式:单击展开对应作业的操作列表,点击SparkUI进入Spark页面,切换到Executors页面,查看Task Time (GC Time)字段。

如果某些Executor GC Time比较多时,您可以采取如下解决方案。

  • 优化逻辑。

  • 增大Executor或Driver的节点规格。

5. 查看Driver或Executor堆栈慢在哪里。

查看方式:单击展开对应作业的操作列表,点击SparkUI进入Spark页面,切换到Executors页面,查看Thread Dump字段。

注意

堆栈只有在作业running状态才能查看。

解决方案:多次刷新堆栈查看作业运行卡在什么地方。

  • 如果集中卡在某一个或者某几个函数调用上,那么说明该部分逻辑有热点或者实现效率比较低,您可以考虑优化该部分逻辑。

  • 如果卡在Spark的某些调用中,您可以通过搜索引擎搜索解决。