在从 Amazon Redshift 插入或提取数据时,为什么我的 AWS Glue 任务失败并返回错误“Temporary directory not specified”?

上次更新日期:2021 年 8 月 13 日

在从 Amazon Redshift 插入或提取数据时,我的 AWS Glue 任务失败并返回错误“Temporary directory not specified”?

简短描述

当您的 AWS Glue 任务从 Amazon Redshift 写入或读取数据时,需要记住以下几点:

  • 您的 AWS Glue 任务将数据写入 Amazon Redshift 集群:该作业先以 CSV 格式将数据写入 Amazon Simple Storage Service (Amazon S3) 存储桶。然后,该作业向 Amazon Redshift 发出 COPY 命令。
  • 您的 AWS Glue 任务从 Amazon Redshift 集群读取数据:该作业首先使用 UNLOAD 命令以 CSV 格式将数据卸载到 Amazon S3 存储桶。然后,该作业再将数据从这些临时存储桶文件加载到 DynamicFrame。

当满足以下任一条件时,您可能会收到此错误消息:

  • 您正在将数据从 Amazon Redshift 卸载到临时 S3 存储桶。
  • 您正在使用 COPY 或 UNLOAD 命令将数据从 S3 存储桶加载到 Amazon Redshift。

解决方法

以下是此错误的一些常见原因和解决方案选项。

定义临时目录

出现此错误的最常见原因是缺少 AWS Glue 任务用作暂存目录的临时 S3 存储桶。因此,请务必将 S3 存储桶定义为任务的临时目录。有关如何定义临时存储桶的更多信息,请参阅 AWS Glue 使用的特殊参数

验证 IAM 角色权限

验证 IAM 角色权限以确保您拥有访问临时 S3 存储桶的适当权限。此外,请确保您没有在以下针对 AWS Glue IAM 角色的策略中阻止存储桶所需的权限:

  • 存储桶策略
  • S3 VPC 终端节点策略
  • AWS Organizations 策略
  • 服务控制策略

所需权限的示例包括 ListObjects、GetObject 和 PutObject。

验证临时目录的名称

请确保用作临时目录的 S3 存储桶的名称中没有句点,以避免出现以下例外情况:

Caused by: java.sql.SQLException: [Amazon](500310) Invalid operation: UNLOAD destination is not supported.

验证 AWS Key Management Service (AWS KMS) 权限

如果您使用 AWS Key Management Service (AWS KMS) 中的客户管理的密钥来加密数据,那么请务必在 AWS Glue 脚本中为 ETL 语句的 additional_options 包括 extraunloadoptions。例如:

datasource0 = glueContext.create_dynamic_frame.from_catalog(
    database = "database-name", 
    table_name = "table-name", 
    redshift_tmp_dir = args["TempDir"],
    additional_options = {"extraunloadoptions":"ENCRYPTED KMS_KEY_ID 'CMK key ID'"}, 
    transformation_ctx = "datasource0"
  )

如果您使用 AWS KMS 加密 S3 数据并面临与 AWS KMS 相关的权限问题,请确保以下事项:

  • 您在 AWS Glue IAM 角色中拥有与下面类似的 AWS KMS 操作权限。
  • 您将 AWS Glue IAM 角色添加到 AWS KMS 密钥中。
"Action": [
    "kms:Encrypt",
    "kms:Decrypt",
    "kms:ReEncrypt*",
    "kms:GenerateDataKey*",
    "kms:DescribeKey"
    ]

验证 AWS Glue Python Shell 任务的 IAM 角色权限

如果您尝试从 AWS Glue Python Shell 任务运行 COPY 或 UNLOAD 命令,但无法加载凭证,请确保以下事项:

  • 您在 Amazon Redshift 中添加了 AWS Glue IAM 角色。
  • AWS Glue 任务角色在其信任关系策略中包括 Amazon Redshift 和 AWS Glue。例如:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "glue.amazonaws.com",
          "redshift.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

检查数据包丢弃

在连接成功后,如果您的查询仍然无法访问 Amazon Redshift 集群,则可能是由于 Amazon Redshift 网络路径与 AWS Glue 网络路径之间的最大传输单位 (MTU) 大小不匹配。尝试配置 Amazon Redshift 安全组以允许“无法访问的 ICMP 目标”。有关更多信息,请参阅查询似乎挂起,有时无法到达集群

在 AWS CloudFormation 模板中定义临时目录

如果您使用 CloudFormation 创建了 AWS Glue 任务,那么请确保您在 CloudFormation 模板的 DefaultArguments 参数中提供了临时目录位置。例如:

"DefaultArguments": { "--TempDir": "s3://doc-example-bucket/doc-example-folder"}

在 DynamicFrame 中定义临时目录

如果在 AWS Glue 任务中定义了临时目录之后仍然出现错误,请检查您是在读取还是写入 Amazon Redshift。您可以使用 AWS Glue 的 DynamicFrame 方法执行此操作。然后确认以下事项:

您已将临时目录传递到 DynamicFrame 的 redshift_tmp_dir 属性中:

您在 getResolvedOptions 函数中为 ETL 任务指定了 TempDir:

使用以下命令检索任务名称和 TempDir 参数:

import sys
from awsglue.utils import getResolvedOptions
args = getResolvedOptions(sys.argv,['JOB_NAME','TempDir'])
TempDir = args['TempDir']

有关更多信息,请参阅使用 getResolvedOptions 访问参数。


这篇文章对您有帮助吗?


您是否需要账单或技术支持?