避免使用 hadoop (EMR) 在 S3 中创建 _$folder$ 键

问题描述 投票:0回答:5

我正在 AWS 数据管道中使用 EMR 活动。此 EMR 活动正在 EMR 集群中运行 Hive 脚本。它以 dynamo DB 作为输入并将数据存储在 S3 中。

这是 EMR 活动中使用的 EMR 步骤

s3://elasticmapreduce/libs/script-runner/script-runner.jar,s3://elasticmapreduce/libs/hive/hive-script,--run-hive-script,--hive-versions,latest,--args,-f,s3://my-s3-bucket/hive/my_hive_script.q,-d,DYNAMODB_INPUT_TABLE1=MyTable,-d,S3_OUTPUT_BUCKET=#{output.directoryPath}

哪里

out.direcoryPath 是:

s3://my-s3-bucket/output/#{format(@scheduledStartTime,"YYYY-MM-dd")}

因此这会在 S3 中创建一个文件夹和一个文件。 (从技术上讲,它创建了两个键

2017-03-18/<some_random_number>
2017-03-18_$folder$

2017-03-18
2017-03-18_$folder$

如何避免创建这些额外的空

_$folder$
文件。

编辑: 我找到了https://issues.apache.org/jira/browse/HADOOP-10400列出的解决方案,但我不知道如何在AWS数据管道中实现它。

amazon-web-services hadoop amazon-s3 amazon-emr
5个回答
17
投票

在写入 s3 存储桶时使用 s3a,它将删除 $folder$。我已经测试过这种胶水。不确定它是否适用于 EMR 集群。

信用:- Reddit 上有人回答

from pyspark.sql import SparkSession
spark=SparkSession.builder.getOrCreate()
df=spark.read.format("parquet").load("s3://testingbucket/")
df.write.format("parquet").save("s3a://testingbucket/parttest/")
spark.stop()

8
投票

EMR 似乎没有提供避免这种情况的方法。

由于S3使用键值对存储系统,Hadoop文件系统通过创建带有“_$folder$”后缀的空文件来实现S3中的目录支持。

您可以安全地删除 S3 存储桶中出现的带有

<directoryname>_$folder$
后缀的任何空文件。这些空文件是由 Hadoop 框架在运行时创建的,但 Hadoop 的设计初衷是即使删除这些空文件也能处理数据。

https://aws.amazon.com/premiumsupport/knowledge-center/emr-s3-empty-files/

它在 Hadoop 源代码中,因此可以修复,但显然在 EMR 中尚未修复。

如果您觉得聪明,您可以创建一个与 _$folder$ 后缀匹配的 S3 事件通知,并让它触发 Lambda 函数以在创建对象后删除它们。


5
投票

S3 中无法实际创建空文件夹。 S3 是一个对象存储,所以里面的一切都是对象。

当Hadoop将其用作文件系统时,它需要组织这些对象,使其显示为文件系统树,因此它创建一些特殊的对象来将对象标记为目录。

你只是存储数据文件,但你可以选择将这些数据文件组织到路径中,这创建了一个类似于用于遍历的文件夹的概念。

包括 AWS 管理控制台在内的一些工具通过解释对象名称中的 /s 来模拟文件夹。 Amazon S3 控制台支持文件夹概念作为对象分组方式。 Bucket Explorer 也是如此。

如果您只是不创建文件夹,而是将文件放在您想要的路径中 - 这应该适合您。

在 S3 中向其中写入文件之前无需创建文件夹,因为

/all/path/including/filename
- 是 S3 存储中的整个密钥。


0
投票

在 EMR 引导操作中使用以下脚本来解决此问题。 AWS 提供的补丁

#!/bin/bash

# NOTE: This script replaces the s3-dist-cp RPM on EMR versions 4.6.0+ with s3-dist-cp-2.2.0.
# This is intended to remove the _$folder$ markers when creating the destination prefixes in S3.

set -ex

RPM=bootstrap-actions/s3-dist-cp-2.2.0/s3-dist-cp-2.2.0-1.amzn1.noarch.rpm

LOCAL_DIR=/var/aws/emr/packages/bigtop/s3-dist-cp/noarch

# Get the region from metadata
REGION=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone/ 2>/dev/null | head -c -1)

# Choose correct bucket for region
if [ $REGION = "us-east-1" ]
then
    BUCKET=awssupportdatasvcs.com
else
    BUCKET=$REGION.awssupportdatasvcs.com
fi

# Download new RPM
sudo rm $LOCAL_DIR/s3-dist-cp*.rpm
aws s3 cp s3://$BUCKET/$RPM /tmp/
sudo cp /tmp/s3-dist-cp-2.2.0-1.amzn1.noarch.rpm $LOCAL_DIR/

echo Rebuilding Repo
sudo yum install -y createrepo
sudo createrepo --update -o /var/aws/emr/packages/bigtop /var/aws/emr/packages/bigtop
sudo yum clean all

0
投票

使用 s3:// 使用 s3a:// 将解决您的问题

发生这种情况是因为您在写入时使用的 S3 路径。

s3:// 与 s3a://

s3:// 将使文件夹 s3a:// 不会

前缀

s3://
s3a://
均用于指定用于访问 Apache Spark 中 Amazon S3 中存储的数据的协议。

  1. s3://
    :该前缀用于指定Spark中访问数据的S3协议。它是 Spark 使用的默认协议,提供从 S3 读取数据和向 S3 写入数据的基本功能。使用
    s3://
    时,Spark 使用 Hadoop S3A 连接器与 S3 交互。

  2. s3a://
    :该前缀也用于指定Spark中访问数据的S3协议。与
    s3://
    相比,它是一种替代协议,提供了额外的功能和优化。使用
    s3a://
    时,Spark 使用 Hadoop S3A 连接器,这是 S3 连接器的改进版本。

一般来说,在使用 Spark 和 S3 时,建议使用

s3a://
而不是
s3://
,因为
s3a://
提供更好的性能和可靠性。但是,
s3://
s3a://
之间的具体选择可能取决于您的具体用例和要求。

例如,要使用

s3://
指定向S3读取或写入数据的输入或输出路径,可以使用以下语法:

inputPath = "s3://your-bucket/your-input-path"
outputPath = "s3://your-bucket/your-output-path"

同样,要使用

s3a://
,您可以将路径中的
s3://
替换为
s3a://

inputPath = "s3a://your-bucket/your-input-path"
outputPath = "s3a://your-bucket/your-output-path"
© www.soinside.com 2019 - 2024. All rights reserved.