3

我正在尝试使用 distcp 将数据从本地 hadoop 集群复制到 S3 存储桶。

有时它“有效”,但一些映射器失败,堆栈跟踪如下。其他时候,太多的映射器失败了,整个工作都取消了。

错误“任何本地目录中都没有可用空间”。对我来说没有意义。边缘节点(运行 distcp 命令的地方)、集群和 S3 存储桶中有大量空间。

任何人都可以对此有所了解吗?

16/06/16 15:48:08 INFO mapreduce.Job: The url to track the job: <url>
16/06/16 15:48:08 INFO tools.DistCp: DistCp job-id: job_1465943812607_0208
16/06/16 15:48:08 INFO mapreduce.Job: Running job: job_1465943812607_0208
16/06/16 15:48:16 INFO mapreduce.Job: Job job_1465943812607_0208 running in uber mode : false
16/06/16 15:48:16 INFO mapreduce.Job:  map 0% reduce 0%
16/06/16 15:48:23 INFO mapreduce.Job:  map 33% reduce 0%
16/06/16 15:48:26 INFO mapreduce.Job: Task Id : attempt_1465943812607_0208_m_000001_0, Status : FAILED
Error: java.io.IOException: File copy failed: hdfs://<hdfs path>/000000_0 --> s3n://<bucket>/<s3 path>/000000_0
        at org.apache.hadoop.tools.mapred.CopyMapper.copyFileWithRetry(CopyMapper.java:285)
        at org.apache.hadoop.tools.mapred.CopyMapper.map(CopyMapper.java:253)
        at org.apache.hadoop.tools.mapred.CopyMapper.map(CopyMapper.java:50)
        at org.apache.hadoop.mapreduce.Mapper.run(Mapper.java:146)
        at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:787)
        at org.apache.hadoop.mapred.MapTask.run(MapTask.java:341)
        at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:168)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAs(Subject.java:415)
        at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1709)
        at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:162)
Caused by: java.io.IOException: Couldn't run retriable-command: Copying hdfs://<hdfs path>/000000_0 to s3n://<bucket>/<s3 path>/000000_0
        at org.apache.hadoop.tools.util.RetriableCommand.execute(RetriableCommand.java:101)
        at org.apache.hadoop.tools.mapred.CopyMapper.copyFileWithRetry(CopyMapper.java:281)
        ... 10 more
Caused by: org.apache.hadoop.util.DiskChecker$DiskErrorException: No space available in any of the local directories.
        at org.apache.hadoop.fs.LocalDirAllocator$AllocatorPerContext.getLocalPathForWrite(LocalDirAllocator.java:366)
        at org.apache.hadoop.fs.LocalDirAllocator$AllocatorPerContext.createTmpFileForWrite(LocalDirAllocator.java:416)
        at org.apache.hadoop.fs.LocalDirAllocator.createTmpFileForWrite(LocalDirAllocator.java:198)
        at org.apache.hadoop.fs.s3native.NativeS3FileSystem$NativeS3FsOutputStream.newBackupFile(NativeS3FileSystem.java:263)
        at org.apache.hadoop.fs.s3native.NativeS3FileSystem$NativeS3FsOutputStream.<init>(NativeS3FileSystem.java:245)
        at org.apache.hadoop.fs.s3native.NativeS3FileSystem.create(NativeS3FileSystem.java:412)
        at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:986)
        at org.apache.hadoop.tools.mapred.RetriableFileCopyCommand.copyToFile(RetriableFileCopyCommand.java:174)
        at org.apache.hadoop.tools.mapred.RetriableFileCopyCommand.doCopy(RetriableFileCopyCommand.java:123)
        at org.apache.hadoop.tools.mapred.RetriableFileCopyCommand.doExecute(RetriableFileCopyCommand.java:99)
        at org.apache.hadoop.tools.util.RetriableCommand.execute(RetriableCommand.java:87)
        ... 11 more
4

4 回答 4

2

我们在尝试将运行结果从 Apache Spark(版本 1.5.2)直接保存到 S3 时遇到了类似的异常。例外是一样的。我不太确定核心问题是什么——不知何故,S3 上传似乎与 Hadoop 的 LocalDirAllocator 类(版本 2.7)“玩得很好”。

最终为我们解决的问题是以下组合:

  1. 启用 S3 的“快速上传”——通过在 Hadoop 配置中将“fs.s3a.fast.upload”设置为“true”。这使用 S3AFastOutputStream 而不是 S3AOutputStream 并直接从内存上传数据,而不是首先分配本地存储

  2. 在保存到 s3 之前将作业结果合并到单个部分(在 Spark 中称为重新分区/合并)

不过有一些注意事项:

  1. S3 的快速上传在Hadoop 2.7中显然被标记为“实验性”

  2. 此解决方法仅适用于较新的 s3a 文件系统(“s3a://...”)。它不适用于较旧的“本机”s3n 文件系统(“s3n://...”)

希望这可以帮助

于 2016-07-04T15:14:56.743 回答
2

理想情况下,您应该使用 s3a 而不是 s3n,因为不推荐使用 s3n。

使用s3a,有一个参数:

<property>
  <name>fs.s3a.buffer.dir</name>
  <value>${hadoop.tmp.dir}/s3a</value>
  <description>Comma separated list of directories that will be used to buffer file
uploads to. No effect if fs.s3a.fast.upload is true.</description>
</property>

当您收到本地文件错误时,很可能是因为缓冲区目录没有空间。

虽然您可以将此设置更改为指向具有更多空间的目录,但更好的解决方案可能是设置(再次在 S3a 中):

fs.s3a.fast.upload=true

这避免了缓冲本地磁盘上的数据,实际上也应该更快。

S3n 缓冲区目录参数应为:

fs.s3.buffer.dir

因此,如果您坚持使用 s3n,请确保它有足够的空间,它应该有望解决这个问题。

于 2017-09-12T09:57:21.223 回答
0

我有几天这个错误并且没有得到发生了什么,所有节点都有充足的空间(大约 400GB)。经过一番研究,我发现:2019-01-09 17:31:30,326 WARN [main] org.apache.hadoop.fs.LocalDirAllocator$AllocatorPerContext: Failed to create /mnt/hadoop/tmp/s3a

异常说的是空间,但真正的错误是权限,消息可以改进。

于 2019-01-09T17:51:57.287 回答
0

我在使用 Hadoop 2.8.5 时遇到了同样的问题,但设置"fs.s3a.fast.upload""true"并没有解决问题。我还必须设置fs.s3a.fast.upload.buffer"bytebuffer". 默认设置fs.s3a.fast.upload.buffer"disk",这解释了为什么我继续得到同样的错误。还有一个"array"设置,但我没有尝试过。

可用的fs.s3a.fast.upload.buffer设置是:

  1. 缓冲到 JVM 堆外内存的字节缓冲区。

  2. 缓冲到 JVM 堆内存的数组。

  3. 磁盘[DEFAULT] 缓冲到本地硬盘。

上面链接的 Hadoop 站点上解释了每个警告。

下面的示例 pySpark 代码。

from pyspark.sql import SparkSession

spark = SparkSession.builder.getOrCreate()
sc = spark.sparkContext

hdpConf = sc._jsc.hadoopConfiguration()
user = os.getenv("USER")
hdpConf.set("hadoop.security.credential.provider.path", "jceks://hdfs/user/{}/awskeyfile.jceks".format(user))
hdpConf.set("fs.s3a.fast.upload", "true")
hdpConf.set("fs.s3a.fast.upload.buffer", "bytebuffer")
于 2020-06-21T19:10:37.607 回答