Java Hadoop中压缩的工作原理

Java Hadoop中压缩的工作原理,java,hadoop,mapreduce,compression,Java,Hadoop,Mapreduce,Compression,在我的MR工作中,比如说,我为map或reduce-output-to-LZO指定了压缩,它是如何被压缩的?是map或REDUCT任务中的全部数据首先在没有压缩的情况下获得,然后在最后,未压缩的数据会被压缩,还是会被增量压缩和写入。如果它被增量压缩和写入,那么它是如何完成的?请帮助我理解这一点 谢谢 Venkat基本上取决于您使用的文件类型。如果它是一个文本文件,则在文件级别进行压缩。但若它是SequenceFile,那个么压缩可能是在记录级或块级。注意,这里的块表示使用序列文件的缓冲区,而不是

在我的MR工作中,比如说,我为map或reduce-output-to-LZO指定了压缩,它是如何被压缩的?是map或REDUCT任务中的全部数据首先在没有压缩的情况下获得,然后在最后,未压缩的数据会被压缩,还是会被增量压缩和写入。如果它被增量压缩和写入,那么它是如何完成的?请帮助我理解这一点

谢谢


Venkat基本上取决于您使用的文件类型。如果它是一个文本文件,则在文件级别进行压缩。但若它是SequenceFile,那个么压缩可能是在记录级或块级。注意,这里的块表示使用序列文件的缓冲区,而不是hdfs块

如果是块压缩,则多个记录一次压缩到一个块中。将记录添加到块中,直到其达到以字节为单位的最小大小。每次要压缩的输入数据的最大大小是通过从缓冲区大小中减去压缩算法的最大开销来计算的。zlib算法的默认缓冲区大小为512字节,压缩开销为18字节(缓冲区大小的1%+12字节)。然后使用给定的输出流和压缩器创建一个BlockCompressorStream,并写入压缩数据


希望这能在一定程度上回答这个问题。

我想我会在Tariq的回答中添加更多的细节,在更高的层次上解释压缩在mapreduce管道中的位置。希望这是有帮助的

如果为映射阶段指定压缩(
mapreduce.map.output.compress=true
),则中间映射输出数据将使用您指定的任何编解码器进行压缩(
mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.
),并在每个映射任务完成时保存到磁盘(如果map任务超出序列化缓冲区限制,并开始溢出到磁盘,则更早)。然后,在mapreduce作业的洗牌和排序阶段,将从磁盘读取压缩数据并发送到相应的节点

在这一阶段(映射输出),压缩结果在可拆分方面没有任何好处,因此GZIP或Snappy编解码器以及LZO和BZIP2都值得在这里尝试。GZIP通常对大多数数据具有更好的压缩比,但会严重消耗CPU,而Snappy速度更快,压缩比更低(也就是说,它要么延迟较小,要么不像GZIP那样消耗CPU…我不确定原因)。使用teragen生成的数据,GZIP与Snappy的压缩比分别为3.5倍和2.5倍。显然,您的数据和硬件限制将决定在您的情况下最有利的编解码器是什么

在shuffle&sort阶段之前进行压缩是很有帮助的,因为它减少了磁盘IO,并且减少了网络带宽,因为您正在通过网络发送压缩的数据。我想不出一个好的理由在这个阶段不压缩数据,只要不争用CPU资源来压缩数据。在我的10节点Hadoop clus中在1GB网络上运行的ter仅在地图输出阶段启用压缩(即,压缩洗牌和排序阶段之前的中间地图数据;未压缩最终输出),将100GB terasort作业的总体作业时间缩短了41%(GZIP),缩短了45%(Snappy)与不使用压缩相比。这些实验中的数据是使用teragen生成的。当然,您的结果会因数据集、硬件和网络而异

然后在reduce阶段开始时对压缩数据进行解压缩


压缩在最终输出(mapreduce.output.fileoutputformat.compress=true)的缩减阶段结束时再次发挥作用。如果要将输出馈送到另一个mapreduce作业中,可拆分LZO或BZIP2压缩可能在这里很有用。如果不在输出上使用可拆分压缩编解码器并在该数据上运行作业,则只能使用单个映射器,这会破坏Hadoop的主要优点之一:并行化。一种解决方法这和使用GZIP编解码器一样,是为了为输出创建一个序列文件。序列文件是可拆分的,因为它本质上是附加在一起的一系列压缩文件。序列文件在每个文件附加到另一个文件的边界处是可拆分的。

感谢Tariq的时间和回复。我主要感兴趣的是因此,如果文件是文本文件,那么首先创建文本文件的未压缩副本,最后将其压缩为单个文件?我想说的是文本文件,但将其错贴为测试文件。