排查 Spark 错误
如果您在 AWS Glue 中遇到错误,可以使用以下信息来帮助您查找问题的根源并解决问题。
注意
AWS Glue GitHub 存储库中的 AWS Glue 常见问题
主题
- 错误:资源不可用
- 错误:在 VPC 中找不到 subnetId 的 S3 终端节点或 NAT 网关
- 错误:需要安全组中的入站规则
- 错误:需要安全组中的出站规则
- 错误:作业运行失败,因为应该向传递的角色授予针对 AWS Glue 服务的代入角色权限
- 错误:DescribeVpcEndpoints 操作未经授权。无法验证 VPC ID vpc-id
- 错误:DescribeRouteTables 操作未经授权。无法验证 VPC ID: vpc-id 中的 subnet id: Subnet-id
- 错误:无法调用 ec2:DescribeSubnets
- 错误:无法调用 ec2:DescribeSecurityGroups
- 错误:找不到可用区的子网
- 错误:对 JDBC 目标进行写入时发生作业运行异常
- 错误:Amazon S3:此操作对该对象的存储类无效
- 错误:Amazon S3 超时
- 错误:Amazon S3 访问被拒绝
- 错误:Amazon S3 访问密钥 ID 不存在
- 错误:作业在访问带有 s3a:// URI 的 Amazon S3 时运行失败
- 错误:Amazon S3 服务令牌已过期
- 错误:找不到网络接口的私有 DNS
- 错误:开发终端节点预置失败
- 错误:笔记本服务器 CREATE_FAILED
- 错误:本地笔记本无法启动
- 错误:运行爬网程序失败
- 错误:分区未更新
- 错误:由于版本不匹配,作业书签更新失败
- 错误:启用作业书签后,作业正在重新处理数据
- 错误:AWS Glue 中 VPC 之间的失效转移行为
错误:资源不可用
如果 AWS Glue 返回了“资源不可用”消息,则可查看错误消息或日志来帮助您详细了解问题。以下作业描述了故障排除的通用方法。
-
对于您使用的任何连接和开发终端节点,请检查您的集群是否未用尽弹性网络接口。
错误:在 VPC 中找不到 subnetId 的 S3 终端节点或 NAT 网关
检查消息中的子网 ID 和 VPC ID 可帮助您诊断问题。
-
检查您是否设置了 AWS Glue 需要的 Amazon S3 VPC 终端节点。此外,请检查您的 NAT 网关 (如果它是您的配置的一部分)。有关更多信息,请参阅 适用于 Amazon S3 的 Amazon VPC 终端节点。
错误:需要安全组中的入站规则
至少有一个安全组必须打开所有入口端口。为限制流量,入站规则中的源安全组可限制为同一安全组。
-
对于您使用的任何连接,请检查安全组中是否有属于自引用的入站规则。有关更多信息,请参阅 设置对数据存储的网络访问。
-
如果您使用的是开发终端节点,请检查安全组中是否有属于自引用的入站规则。有关更多信息,请参阅 设置对数据存储的网络访问。
错误:需要安全组中的出站规则
至少有一个安全组必须打开所有出口端口。为限制流量,出站规则中的源安全组可限制为同一安全组。
-
对于您使用的任何连接,请检查安全组中是否有属于自引用的出站规则。有关更多信息,请参阅 设置对数据存储的网络访问。
-
如果您使用的是开发终端节点,请检查安全组中是否有属于自引用的出站规则。有关更多信息,请参阅 设置对数据存储的网络访问。
错误:作业运行失败,因为应该向传递的角色授予针对 AWS Glue 服务的代入角色权限
定义作业的用户必须具有针对适用于 AWS Glue 的 iam:PassRole
的权限。
-
当某个用户创建 AWS Glue 任务时,请确认该用户的角色包含一个策略,其中包含适用于 AWS Glue 的
iam:PassRole
。有关更多信息,请参阅 步骤 3:将策略附加到访问 AWS Glue 的用户或组。
错误:DescribeVpcEndpoints 操作未经授权。无法验证 VPC ID vpc-id
-
检查传递到 AWS Glue 的策略是否有
ec2:DescribeVpcEndpoints
权限。
错误:DescribeRouteTables 操作未经授权。无法验证 VPC ID: vpc-id 中的 subnet id: Subnet-id
-
检查传递到 AWS Glue 的策略是否有
ec2:DescribeRouteTables
权限。
错误:无法调用 ec2:DescribeSubnets
-
检查传递到 AWS Glue 的策略是否有
ec2:DescribeSubnets
权限。
错误:无法调用 ec2:DescribeSecurityGroups
-
检查传递到 AWS Glue 的策略是否有
ec2:DescribeSecurityGroups
权限。
错误:找不到可用区的子网
-
可用区可能对 AWS Glue 不可用。请在不同于消息中指定的可用区的可用区中创建和使用新子网。
错误:对 JDBC 目标进行写入时发生作业运行异常
当您运行某个对 JDBC 目标进行写入的作业时,该作业在以下情况下可能遇到错误:
-
如果您的作业对 Microsoft SQL Server 表进行写入,而该表具有定义为
Boolean
类型的列,则必须在 SQL Server 数据库中预定义该表。当您通过 Create tables in your data target (在数据目标中创建表) 选项来使用 SQL Server 目标在 AWS Glue 控制台上定义任务时,请勿将任何源列映射到数据类型为Boolean
的目标列。您可能在作业运行时遇到错误。您可以通过执行以下操作来避免错误:
-
选择包含 Boolean 列的现有表。
-
编辑
ApplyMapping
转换并将源中的 Boolean 列映射到目标中的数字或字符串。 -
编辑
ApplyMapping
转换以从源中删除 Boolean 列。
-
-
如果您的作业对 Oracle 表进行写入,您可能需要调整 Oracle 对象的名称长度。在某些版本的 Oracle 中,最大标识符长度限制为 30 个字节或 128 个字节。此限制影响 Oracle 目标数据存储的表名称和列名称。
您可以通过执行以下操作来避免错误:
-
在您的版本的限制内为 Oracle 目标表命名。
-
默认列名称从数据中的字段名称生成。要应对列名称长度超过限制的情况,请使用
ApplyMapping
或RenameField
转换将列的名称更改得不超过限制。
-
错误:Amazon S3:此操作对该对象的存储类无效
如果 AWS Glue 返回此错误,则说明 AWS Glue 作业可能正在从跨 Amazon S3 存储类层级进行分区的表中读取数据。
-
通过使用存储类排除,您可以确保您的 AWS Glue 作业可以在具有跨这些存储类层的分区的表上工作。如果没有排除项,则从这些层读取数据的作业将会失败,并显示以下错误:
AmazonS3Exception: The operation is not valid for the object's storage class
。有关更多信息,请参阅 排除 Amazon S3 存储类。
错误:Amazon S3 超时
如果 AWS Glue 返回连接超时错误,则可能是因为它正在尝试访问其他 AWS 区域中的 Amazon S3 存储桶。
-
Amazon S3 VPC 终端节点只能将流量路由到 AWS 区域中的存储桶。如果您需要连接到其他区域中的存储桶,一种可能的解决方法是使用 NAT 网关。有关更多信息,请参阅 NAT 网关。
错误:Amazon S3 访问被拒绝
如果 AWS Glue 向 Amazon S3 存储桶或对象返回了“访问被拒绝”错误,则可能是因为提供的 IAM 角色没有具有针对您的数据存储的权限的策略。
-
ETL 任务必须有权访问用作源或目标的 Amazon S3 数据存储。爬网程序必须有权访问其爬取的 Amazon S3 数据存储。有关更多信息,请参阅 步骤 2:为 AWS Glue 创建 IAM 角色。
错误:Amazon S3 访问密钥 ID 不存在
如果AWS Glue 在运行作业时返回了“访问密钥 ID 不存在”错误,则可能由以下原因之一导致:
-
ETL 任务使用 IAM 角色来访问数据存储和确认您的任务的 IAM 角色在任务开始前未被删除。
-
IAM 角色包含以下权限:访问您的数据存储和确认包含
s3:ListBucket
的所有已附加的 Amazon S3 策略正确无误。
错误:作业在访问带有 s3a://
URI 的 Amazon S3 时运行失败
如果作业运行时返回一个类似无法分析使用处理程序类的 XML 文档的错误,可能是由于尝试列出数百个使用 s3a://
URI 的文件时失败。改用 s3://
URI 访问您的数据存储。下面的异常跟踪突出显示了要查找的错误:
1. com.amazonaws.SdkClientException: Failed to parse XML document with handler class com.amazonaws.services.s3.model.transform.XmlResponsesSaxParser$ListBucketHandler 2. at com.amazonaws.services.s3.model.transform.XmlResponsesSaxParser.parseXmlInputStream(XmlResponsesSaxParser.java:161) 3. at com.amazonaws.services.s3.model.transform.XmlResponsesSaxParser.parseListBucketObjectsResponse(XmlResponsesSaxParser.java:317) 4. at com.amazonaws.services.s3.model.transform.Unmarshallers$ListObjectsUnmarshaller.unmarshall(Unmarshallers.java:70) 5. at com.amazonaws.services.s3.model.transform.Unmarshallers$ListObjectsUnmarshaller.unmarshall(Unmarshallers.java:59) 6. at com.amazonaws.services.s3.internal.S3XmlResponseHandler.handle(S3XmlResponseHandler.java:62) 7. at com.amazonaws.services.s3.internal.S3XmlResponseHandler.handle(S3XmlResponseHandler.java:31) 8. at com.amazonaws.http.response.AwsResponseHandlerAdapter.handle(AwsResponseHandlerAdapter.java:70) 9. at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleResponse(AmazonHttpClient.java:1554) 10. at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1272) 11. at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1056) 12. at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:743) 13. at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:717) 14. at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:699) 15. at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:667) 16. at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:649) 17. at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:513) 18. at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4325) 19. at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4272) 20. at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4266) 21. at com.amazonaws.services.s3.AmazonS3Client.listObjects(AmazonS3Client.java:834) 22. at org.apache.hadoop.fs.s3a.S3AFileSystem.getFileStatus(S3AFileSystem.java:971) 23. at org.apache.hadoop.fs.s3a.S3AFileSystem.deleteUnnecessaryFakeDirectories(S3AFileSystem.java:1155) 24. at org.apache.hadoop.fs.s3a.S3AFileSystem.finishedWrite(S3AFileSystem.java:1144) 25. at org.apache.hadoop.fs.s3a.S3AOutputStream.close(S3AOutputStream.java:142) 26. at org.apache.hadoop.fs.FSDataOutputStream$PositionCache.close(FSDataOutputStream.java:74) 27. at org.apache.hadoop.fs.FSDataOutputStream.close(FSDataOutputStream.java:108) 28. at org.apache.parquet.hadoop.ParquetFileWriter.end(ParquetFileWriter.java:467) 29. at org.apache.parquet.hadoop.InternalParquetRecordWriter.close(InternalParquetRecordWriter.java:117) 30. at org.apache.parquet.hadoop.ParquetRecordWriter.close(ParquetRecordWriter.java:112) 31. at org.apache.spark.sql.execution.datasources.parquet.ParquetOutputWriter.close(ParquetOutputWriter.scala:44) 32. at org.apache.spark.sql.execution.datasources.FileFormatWriter$SingleDirectoryWriteTask.releaseResources(FileFormatWriter.scala:252) 33. at org.apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$org$apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask$3.apply(FileFormatWriter.scala:191) 34. at org.apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$org$apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask$3.apply(FileFormatWriter.scala:188) 35. at org.apache.spark.util.Utils$.tryWithSafeFinallyAndFailureCallbacks(Utils.scala:1341) 36. at org.apache.spark.sql.execution.datasources.FileFormatWriter$.org$apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask(FileFormatWriter.scala:193) 37. at org.apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$write$1$$anonfun$3.apply(FileFormatWriter.scala:129) 38. at org.apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$write$1$$anonfun$3.apply(FileFormatWriter.scala:128) 39. at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:87) 40. at org.apache.spark.scheduler.Task.run(Task.scala:99) 41. at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:282) 42. at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) 43. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 44. at java.lang.Thread.run(Thread.java:748)
错误:Amazon S3 服务令牌已过期
在将数据移入和移出 Amazon Redshift 时,使用了将在 1 小时后过期的临时 Amazon S3 凭证。如果您有长时间运行的作业,它可能会失败。有关如何设置您的长时间运行的任务以将数据移入和移出 Amazon Redshift 的信息,请参阅aws-glue-programming-etl-connect-redshift-home。
错误:找不到网络接口的私有 DNS
如果作业失败或开发终端节点无法预置,则可能是因为网络设置有问题。
-
如果您使用的是 Amazon 提供的 DNS,则值
enableDnsHostnames
必须设置为 true。有关更多信息,请参阅 DNS。
错误:开发终端节点预置失败
如果 AWS Glue 无法成功预置开发终端节点,则可能是因为网络设置有问题。
-
当您定义开发终端节点时,系统将验证 VPC、子网和安全组以确认它们是否满足特定要求。
-
如果您提供了可选的 SSH 公有密钥,请检查它是否为有效的 SSH 公有密钥。
-
在 VPC 控制台中检查您的 VPC 是否使用了有效的 DHCP 选项集。有关更多信息,请参阅 DHCP 选项集。
-
如果集群仍处于 PROVISIONING 状态,请联系 AWS Support。
错误:笔记本服务器 CREATE_FAILED
如果 AWS Glue 无法为开发终端节点创建笔记本服务器,则可能由以下问题之一导致:
-
AWS Glue 在设置笔记本服务器时会将一个 IAM 角色传递到 Amazon EC2。该 IAM 角色必须与 Amazon EC2 具有信任关系。
-
该 IAM 角色必须具有同名的实例配置文件。当您使用 IAM 控制台为 Amazon EC2 创建角色时,将自动创建与该角色同名的实例配置文件。请在日志中检查与无效的实例配置文件名称
iamInstanceProfile.name
有关的错误。有关更多信息,请参阅使用实例配置文件。 -
检查您的角色是否有权访问您传递的用来创建笔记本服务器的策略中的
aws-glue*
存储桶。
错误:本地笔记本无法启动
如果您的本地笔记本无法启动并报告“找不到某个目录或文件夹”错误,则可能由以下问题之一导致:
-
如果您是在 Microsoft Windows 上运行,请确保
JAVA_HOME
环境变量指向正确的 Java 目录。您可以在不更新此变量的情况下更新 Java,而如果它指向的文件夹不再存在,Jupyter Notebook 将无法启动。
错误:运行爬网程序失败
如果 AWS Glue 无法成功运行爬网程序以便为您的数据编制目录,则可能由以下原因之一导致。首先检查 AWS Glue 控制台爬网程序列表中是否列出了错误。检查爬网程序名称旁边是否有 感叹号图标,并将鼠标指针悬停在该图标上以查看任何相关消息。
-
在 CloudWatch Logs 中的
/aws-glue/crawlers
下检查爬网程序运行的日志。
错误:分区未更新
如果您在运行 ETL 任务时未在数据目录中更新您的分区,则 CloudWatch Logs 的 DataSink
类中的这些日志语句可能会有所帮助:
-
“
Attempting to fast-forward updates to the Catalog - nameSpace:
”— 显示该作业试图修改哪个数据库、表和 catalogId。如果此处没有此语句,请检查enableUpdateCatalog
是否设置为 true 并作为getSink()
参数正确地传递到additional_options
中。 -
“
Schema change policy behavior:
”— 显示您传入的架构updateBehavior
值。 -
“
Schemas qualify (schema compare):
”– 将为 true 或 false。 -
“
Schemas qualify (case-insensitive compare):
”– 将为 true 或 false。 -
如果两者都为 false 并且您的
updateBehavior
未设置为UPDATE_IN_DATABASE
,则 DynamicFrame 架构必须完全相同或包含数据目录表架构中看到的列的子集。
有关更新分区的更多信息,请参阅 使用 AWS Glue ETL 任务在 Data Catalog 中更新架构并添加新分区。
错误:由于版本不匹配,作业书签更新失败
您可能正在尝试参数化 AWS Glue 作业,以将相同转换/逻辑应用于 Amazon S3 中的不同数据集。您想在提供的位置跟踪处理过的文件。当您在同一源存储桶上运行同一作业并同时写入相同/不同目标(并发 > 1)时,该作业将失败并显示此错误:
py4j.protocol.Py4JJavaError: An error occurred while callingz:com.amazonaws.services.glue.util.Job.commit.:com.amazonaws.services.gluejobexecutor.model.VersionMismatchException: Continuation update failed due to version mismatch. Expected version 2 but found version 3
解决方案:将并发设置为 1,或不同时运行该作业。
目前 AWS Glue 书签不支持并发作业运行,因此提交将失败。
错误:启用作业书签后,作业正在重新处理数据
有些情况下,在您已启用 AWS Glue 作业书签后,您的 ETL 作业还在重新处理早期运行中已处理的数据。检查此错误的以下常见原因:
最大并发数
如果将作业的最大并发运行次数设置为大于默认值 1 的值,可能会干扰作业书签。作业书签检查对象的上次修改时间以验证哪些对象需要重新处理时可能出现这种情况。有关更多信息,请参阅在 AWS Glue 中为 Spark 作业配置作业属性中的最大并发数讨论。
缺少作业对象
确保您的作业运行脚本以下面的提交结束:
job.commit()
当您包含此对象时,AWS Glue 将记录作业运行的时间戳和路径。如果您使用相同路径再次运行该作业,AWS Glue 将只处理新文件。如果您未包含此对象并且已启用作业书签,该作业将重新处理已处理的文件和新文件,并在作业的目标数据存储中创建冗余。
缺少转换上下文参数
转换上下文是 GlueContext
类中的一个可选参数,但如果不包含该参数,作业书签将不起作用。要解决此错误,请在创建 DynamicFrame 时添加转换上下文参数,如下所示:
sample_dynF=create_dynamic_frame_from_catalog(database, table_name,transformation_ctx="sample_dynF")
输入源
如果将关系数据库(JDBC 连接)用作输入源,则仅当表的主键按顺序排列时,作业书签才起作用。作业书签适用于新行,但不适用于更新的行。这是因为作业书签查找已存在的主键。如果您的输入源为 Amazon Simple Storage Service(Amazon S3),则这不适用。
上次修改时间
对于 Amazon S3 输入源,任务书签将通过检查对象的上次修改时间而不是文件名来验证哪些对象需要重新处理。如果您的输入源数据在上次作业运行后已修改,则再次运行作业时将重新处理这些文件。
错误:AWS Glue 中 VPC 之间的失效转移行为
在 AWS Glue 4.0 及之前版本中,以下过程用于作业的失效转移。
摘要:在提交作业运行时选择 AWS Glue 连接。如果作业运行遇到一些问题(缺少 IP 地址、与源的连接、路由问题),则作业运行将失败。如果配置了重试,则 AWS Glue 将使用相同的连接重试。
-
对于每次运行尝试,AWS Glue 都会按照作业配置中列出的顺序检查连接的运行状况,直至找到可以使用的连接为止。如果某个可用区(AZ)出现故障,则来自该可用区的连接将无法通过检查并会被跳过。
-
AWS Glue 使用以下内容验证连接:
检查 Amazon VPC ID 和子网是否有效。
检查 NAT 网关或 Amazon VPC 端点是否存在。
检查子网分配的 IP 地址是否超过 0 个。
检查可用区是否运行正常。
提交作业运行时 AWS Glue 无法验证连接。
-
对于使用 Amazon VPC 的作业,所有驱动程序和执行程序都将在同一个可用区中创建,并在提交作业运行时选择连接。
-
如果配置了重试,则 AWS Glue 将使用相同的连接重试。这是因为我们不能保证此连接的问题是长期存在的。如果某个可用区出现故障,则该可用区中运行的现有作业(取决于作业运行的阶段)可能会失败。重试应该会检测到可用区故障,然后为新的运行选择另一个可用区。