Hadoop 将snappy压缩文件加载到Elastic MapReduce中

Hadoop 将snappy压缩文件加载到Elastic MapReduce中,hadoop,amazon-web-services,compression,hadoop-streaming,emr,Hadoop,Amazon Web Services,Compression,Hadoop Streaming,Emr,我在S3中有一堆snappy压缩服务器日志,我需要在Elastic MapReduce上使用流处理它们。我如何告诉Amazon和Hadoop日志已经被压缩(在它们被拉入HFS之前!),以便在发送到流映射器脚本之前可以对它们进行解压缩 我能找到的唯一文档如下: ,它似乎指的是中间压缩,而不是到达HFS时压缩的文件 顺便说一句,我主要在python中工作,所以如果您有boto中的解决方案,那么您将获得额外的积分 假设您使用的是TextInputFormat(或其子类之一),则会自动处理扩展名为.sn

我在S3中有一堆snappy压缩服务器日志,我需要在Elastic MapReduce上使用流处理它们。我如何告诉Amazon和Hadoop日志已经被压缩(在它们被拉入HFS之前!),以便在发送到流映射器脚本之前可以对它们进行解压缩

我能找到的唯一文档如下: ,它似乎指的是中间压缩,而不是到达HFS时压缩的文件


顺便说一句,我主要在python中工作,所以如果您有boto中的解决方案,那么您将获得额外的积分

假设您使用的是TextInputFormat(或其子类之一),则会自动处理扩展名为.snappy的压缩输入文件

您可能想考虑使用LZO压缩(.gz扩展)而不是快照。为了获得更好的压缩比和可拆分的输入文件,您放弃了一些压缩速度。Cloudera提到这一点:

需要注意的一点是,Snappy旨在与 容器格式,如序列文件或Avro数据文件,而不是 例如,直接用于纯文本,因为后者是 不可拆分,无法使用MapReduce并行处理。 这与LZO不同,LZO可以对LZO压缩进行索引 用于确定分割点的文件,以便可以处理LZO文件 在后续处理中高效地执行

答案是,“这是不可能的。”至少,对于将hadoop流应用于源于hadoop之外的snappy压缩文件的特定情况,情况并非如此

为了得出这个结论,我(彻底地!)研究了两个主要选项:(1)尝试使用HighlyAffinated建议的hadoop内置snappy压缩,或者(2)编写自己的流媒体模块来使用和解压缩snappy文件

对于选项(1),hadoop似乎在使用snappy压缩文件时向文件添加了一些标记。由于我的文件是使用snappy outside hadoop压缩的,hadoop的内置编解码器无法解压缩文件

此问题的一个症状是堆空间错误:

2013-04-03 20:14:49,739 FATAL org.apache.hadoop.mapred.Child (main): Error running child : java.lang.OutOfMemoryError: Java heap space
    at org.apache.hadoop.io.compress.BlockDecompressorStream.getCompressedData(BlockDecompressorStream.java:102)
    at org.apache.hadoop.io.compress.BlockDecompressorStream.decompress(BlockDecompressorStream.java:82)
    at org.apache.hadoop.io.compress.DecompressorStream.read(DecompressorStream.java:76)
    at java.io.InputStream.read(InputStream.java:85)
    ...
当我切换到更大的实例并启动mapred.child.java.opts设置时,出现了一个新错误:

java.io.IOException: IO error in map input file s3n://my-bucket/my-file.snappy
Hadoop的snappy编解码器无法处理外部生成的文件

对于选项(2),问题是hadoop流媒体无法区分\n、\r和\r\n换行符。由于snappy压缩最终会在压缩文件中散布这些字节码,这是致命的。以下是我的错误跟踪:

2013-04-03 22:29:50,194 WARN org.apache.hadoop.mapred.Child (main): Error running child
java.lang.RuntimeException: PipeMapRed.waitOutputThreads(): subprocess failed with code 1
    at org.apache.hadoop.streaming.PipeMapRed.waitOutputThreads(PipeMapRed.java:372)
    at org.apache.hadoop.streaming.PipeMapRed.mapRedFinished(PipeMapRed.java:586)
    at org.apache.hadoop.streaming.PipeMapper.close(PipeMapper.java:135)
    at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:57)
    ...
只需对hadoop的Java类做一点工作(例如,请参阅),我们就可以修复\r\n问题。但正如我最初所说,我的目标是在hadoop流模块中构建,而不涉及Java。有了这个限制,似乎没有任何办法解决这个问题

最后,我回到生成这个集群正在使用的文件的人那里,说服他们切换到gzip或lzo

PS-在选项(2)中,我尝试了在不同的字符上拆分记录(例如textinputformat.record.delimiter=X),但它感觉非常粗糙,并且无论如何都不起作用


PPS-另一种解决方法是编写脚本从S3下载文件,解压缩它们,然后运行-copyFromLocal将它们拉入HDFS。从计算上来说,这没有什么问题,但从工作流的角度来看,这会带来各种麻烦。

我听到了你关于LZO和snappy的说法,对于将来做类似事情的其他人,我也推荐LZO。在我的例子中,管理S3存储的团队有其他理由选择snappy,这不会严重影响我们在hadoop中的性能。因此,我们坚持使用snappy压缩。此外,您提到的基于魔法文件扩展名的检测在hadoop的许多版本上都不起作用。我正在使用AWS EMR AMI 2.3.3,版本1.0.3,但它在那里不起作用。我也尝试过其他几个EMR构建,但没有乐趣。