如何排查 Amazon Redshift 中的 UNLOAD 问题?

上次更新日期:2022 年 10 月 7 日

我正在尝试将数据从我的 Amazon Redshift 集群卸载到 Amazon Simple Storage Service (Amazon S3)。但发生了错误。如何排查此问题?

简短描述

将数据从 Amazon Redshift 集群卸载到 Amazon S3 桶时,您可能会遇到以下错误:

数据库用户无权代入 AWS Identity and Access Management(IAM)角色错误

error:  User arn:aws:redshift:us-west-2:<account-id>:dbuser:<cluster-identifier>/<dbuser username> is not authorized to assume IAM Role arn:aws:iam::<account-id>:role/<Role name>

403 访问被拒绝错误

[Amazon](500310) Invalid operation: S3ServiceException:Access Denied,Status 403,Error AccessDenied,

注意:将数据卸载到 S3 存储桶时,请使用带 SELECT 语句的 UNLOAD 命令。以分隔格式或固定宽度格式卸载文本数据(无论加载时使用的数据格式如何)。您还可以指定是否应该归档压缩的 gzip 文件。

S3 上指定的卸载目标不为空

ERROR: Specified unload destination on S3 is not empty. Consider using a different bucket / prefix, manually removing the target files in S3, or using the ALLOWOVERWRITE option.

当您尝试运行相同的 UNLOAD 命令并在已经存在数据文件的同一个文件夹中卸载文件时,可能会发生此错误。

例如,如果您运行以下命令两次,就会出现此错误:

unload ('select * from test_unload')   
to 's3://testbucket/unload/test_unload_file1' 
iam_role 'arn:aws:iam::0123456789:role/redshift_role';

解决方法

数据库用户无权代入 AWS IAM 角色错误

如果数据库用户无权代入 IAM 角色,请检查以下内容:

403 访问被拒绝错误

如果您收到来自 S3 桶的 403 访问被拒绝错误,请确认已为您的 S3 API 操作授予适当的权限:

"Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:Get*",       
        "s3:List*",
        "s3:PutObject"
      ],
      "Resource": [
        "arn:aws:s3:::your_bucket",
        "arn:aws:s3:::your_bucket/*"
      ]
    }
  ]
}

如果您将服务器端加密与 S3 托管的加密密钥结合使用,则 S3 桶会使用唯一密钥对其每个对象进行加密。作为额外的保护措施,密钥本身也使用定期轮换的根密钥进行加密。

要加密已卸载的静态数据,请验证 S3 桶策略中的 s3:x-amz-server-side-encryption 参数是否设置为“true”:

"Condition": {
   "Null": {
           "s3:x-amz-server-side-encryption": "true"
           }

确认 KMS_KEY_ID 已加密,以便您可以将加密的数据 UNLOAD 到 S3 桶:

unload ('select * from a') to 's3://mybucket/test/varchar/' iam_role 'arn:aws:iam::xxxxxx:role/RedshiftS3Access' ALLOWOVERWRITE CSV
KMS_KEY_ID '11111111111111111111111111'
encrypted;

如果您的 S3 桶使用 AWS Key Management Service (AWS KMS) 中的根密钥进行加密,请将以下权限添加到您的 IAM policy 中:

"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]

S3 上指定的卸载目标不为空

如果您尝试在存在相同文件名的文件夹中UNLOAD(卸载)文件,则会出现 S3 上指定的卸载目标不为空错误。

选择以下选项之一来解决错误消息:

  • 创建新的 Amazon S3 桶或使用不同的 S3 桶
  • 更改 S3 密钥前缀
  • 清理目标 Amazon S3 桶中存在的文件
  • UNLOAD 命令中使用 ALLOWOVERWRITE 选项

创建新的 Amazon S3 桶或使用不同的 S3 桶

1.    创建新的 S3 桶或识别不同的现有 S3 桶。

2.    为您的桶或现有桶更新 S3 桶的桶策略。必须将以下示例策略添加为权限策略:

{
    "Version": "2012-10-17",
    "Id": "ExamplePolicy01",
    "Statement": [
        {
            "Sid": "ExampleStatement01",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::0123456789:user/<UserName>"
            },
            "Action": [
                "s3:GetObject",
                "s3:GetBucketLocation",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::testbucket/*",
                "arn:aws:s3:::testbucket",
                "arn:aws:s3:::testbucket2/*",  --> Additional permission for new bucket
                "arn:aws:s3:::testbucket2"       
            ]
        }
    ]
}

3.    在 UNLOAD 命令中使用新的桶路径。在以下示例中,s3://testbucket2/unload/test_unload_file1 是新的桶路径:

iam_role 'arn:aws:iam::0123456789:role/redshift_role';
unload ('select * from test_unload')   
to 's3://testbucket2/unload/test_unload_file1'

更改 S3 密钥前缀

使用 UNLOAD 命令时,更改 S3 路径中的 S3 Bucket Key (桶密钥)前缀。在以下示例中,unload2 是更改后的前缀:

iam_role 'arn:aws:iam::0123456789:role/redshift_role';
unload ('select * from test_unload')   
to 's3://testbucket/unload2/test_unload_file1'

有关更多信息,请参阅使用前缀整理对象

清理目标 Amazon S3 桶中存在的文件

在将文件卸载到指定位置之前,使用 CLEANPATH 选项删除位于 TO 子句中指定的 Amazon S3 路径中的现有文件。如果包含 PARTITION BY 子句,则仅从分区文件夹中删除现有文件。这允许 Amazon S3 桶接收由 UNLOAD 操作生成的新文件。

重要提示:使用 CLEANPATH 选项删除的文件将被永久删除且无法恢复。

要使用 CLEANPATH 选项,您必须拥有 Amazon S3 桶的 s3: DeleteObject 权限。必须将以下示例策略添加为权限策略:

{
    "Version": "2012-10-17",
    "Id": "ExamplePolicy01",
    "Statement": [
        {
            "Sid": "ExampleStatement01",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::0123456789:user/<UserName>"
            },
            "Action": [
                "s3:GetObject",
                "s3:GetBucketLocation",
                "s3:ListBucket",
                "s3:DeleteObject"  --> Additional Action added for delete object
            ],
            "Resource": [
                "arn:aws:s3:::testbucket/*",
                "arn:aws:s3:::testbucket"
            ]
        }
    ]
}

注意:如果您指定 ALLOWOVERWRITE 选项,则无法指定 CLEANPATH 选项。

在 UNLOAD 命令中使用 ALLOWOVERWRITE 选项

如果 UNLOAD 命令找到可能被覆盖的文件,则该命令失败。如果指定了 ALLOWOVERWRITE,则 UNLOAD 会覆盖现有文件,包括清单文件。在以下示例中,之前的文件被覆盖,桶已更新新记录。

iam_role 'arn:aws:iam::0123456789:role/redshift_role' allowoverwrite;
unload ('select * from test_unload')   
to 's3://testbucket/unload/test_unload_file1'

要使用 ALLOWOVERWRITE 选项,您必须拥有 Amazon S3 桶的 s3:PutObject 权限。必须将以下示例策略添加为权限策略:

{
    "Version": "2012-10-17",
    "Id": "ExamplePolicy01",
    "Statement": [
        {
            "Sid": "ExampleStatement01",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::0123456789:user/<UserName>"
            },
            "Action": [
                "s3:GetObject",
                "s3:GetBucketLocation",
                "s3:ListBucket",
                "s3:PutObject"  --> Additional Action added for overwriting objects
            ],
            "Resource": [
                "arn:aws:s3:::testbucket/*",
                "arn:aws:s3:::testbucket"
            ]
        }
    ]
}