5.2 基于压缩的高效存储(续)

(仅包括技术27)

技术27 在MapReduce,Hive和Pig中使用可分块的LZOP

如果一个文本文件即使经过压缩后仍然比HDFS的块的大小要大,就需要考虑选择一个支持分块的压缩编码器,以防一个单一的map任务来处理整个超大的文件。

LZOP可以满足分块的要求,但是使用起来很复杂。原因在于LZOP不是直接支持分块。LZOP是基于块的格式,但是并不支持块的随机访问。

问题

需要选择一个压缩编码器使MapReduce可以调用多个任务并行处理一个单一的压缩文件。

方案

在MapReduce中,对LZOP压缩的输入文件进行分块需要使用针对LZOP的输入格式类,如LzoInputFormat。在Pig和Hive中使用LZOP也是如此。

讨论

压缩编码器中只有LZOP和bzip2支持分块。Bzip2压缩太慢,以至于不太可靠。LZOP在压缩率和速度之间取得了相对可靠的平衡。

在集群配置LZOP

不幸的是,由于授权原因,Hadoop并没有自带LZOP。要在集群中将一切准备工作做好将非常费劲。附录A.10中有配置LZOP的具体步骤。(译注:附录A.10的翻译见下一篇翻译文章。http://www.cnblogs.com/datacloud/p/3617586.html

在HDFS中读写LZOP文件

在此前的技术中(技术25, 26)介绍了如何读取并写入压缩文件。读写LZOP需要在代码中指定LZOP编码器。实现代码如下所示:

Methods to read and write LZOP files in HDFS

 public static Path compress(Path src, Configuration config)
throws IOException { Path destFile = new Path(src.toString() + new LzopCodec().getDefaultExtension());
LzopCodec codec = new LzopCodec();
codec.setConf(config);
FileSystem hdfs = FileSystem.get(config);
InputStream is = null; OutputStream os = null; try {
is = hdfs.open(src);
os = codec.createOutputStream(hdfs.create(destFile));
IOUtils.copyBytes(is, os, config);
} finally {
IOUtils.closeStream(os);
IOUtils.closeStream(is);
} return destFile;
} public static void decompress(Path src, Path dest, Configuration config)
throws IOException { LzopCodec codec = new LzopCodec();
codec.setConf(config);
FileSystem hdfs = FileSystem.get(config);
InputStream is = null;
OutputStream os = null; try {
is = codec.createInputStream(hdfs.open(src));
os = hdfs.create(dest);
IOUtils.copyBytes(is, os, config);
} finally {
IOUtils.closeStream(os);
IOUtils.closeStream(is);
}
}

然后写入并读取一个LZOP文件,确保LZOP工具可以操作生成的文件。脚本如下所示:

$ hadoop fs -put $HADOOP_HOME/conf/core-site.xml core-site.xml

$ bin/run.sh com.manning.hip.ch5.LzopFileReadWrite core-site.xml

上述代码将在HDFS中生成一个core-site.xml.lzo文件。现在需要确定可以通过lzop程序来处理这个LZOP文件。操作步骤如下:

  1. 在主机上安装lzop程序。(RedHat和Centos上可以从http://pkgs.repoforge.org/lzop/lzop-1.03-1.el5.rf.x86_64.rpm 安装。)
  2. 将LZOP文件从HDFS上拷贝到本地磁盘。
  3. 使用lzop程序解压缩这个LZOP文件。
  4. 将解压缩后的文件和原始文件进行对比。

操作脚本如下:

$ hadoop fs -get core-site.xml.lzo /tmp/core-site.xml.lzo

$ lzop -l /tmp/core-site.xml.lzo

method compressed uncompr. ratio uncompressed_name
LZO1X-1 454 954 47.6% core-site.xml $ cd /tmp $ lzop -d core-site.xml.lzo $ ls -ltr -rw-r--r-- 1 aholmes aholmes 954 Sep 11 09:05 core-site.xml
-rw-r--r-- 1 aholmes aholmes 504 Sep 11 09:05 core-site.xml.lzo $ diff core-site.xml $HADOOP_HOME/conf/core-site.xml
$

通过diff程序的比较,说明使用LZOP编码器压缩的文件可以被lzop程序解压缩。然后就需要为LZOP文件建立索引,使它可以被分块。

为LZOP文件创建索引

LZOP支持分块,但是不支持随机访问。这是因为LZOP没有存储每个块的地址信息(地址偏移量)。那么现在需要做的就是创建一个包含LZOP压缩文件中每个块的地址信息(地址偏移量)的索引。创建方法如图5.5所示,遍历一次LZOP的压缩文件,将每个块的地址偏移量保存在索引文件中。索引文件是一个包含了一系列连续的64位的数字。这些数字包含了LZOP压缩文件中每个块的地址偏移量。

有两种方法可以创建索引文件,正如下面的两个代码片段。如果只是要为一个LZOP文件创建一个索引文件,以下就是一个可以完成这个目标的简单库:

shell$ bin/run.sh \
com.hadoop.copmression.lzo.DistributedLzoIndexer \
core.site.xml.lzo \
/path/to/lzop

如果需要批量处理LZOP文件,生成索引,那么就需要更简便的方法。下面这段代码调用一个MapReduce作业来创建索引文件。它通过遍历文件夹中的LZOP文件来支持文件夹作为输入源。也可以以文件作为输入源。

shell$ bin/run.sh \
com.hadoop.copmression.lzo.DistributedLzoIndexer \
core.site.xml.lzo \
/path/to/lzop

前述两段代码都会在LZOP文件的同一个目录下生成一个索引文件。索引文件的文件名是在原LZOP文件名后面加上.index。以上代码会生成文件名为core-site.xml.lzo.index的索引文件。接下来介绍如何在JAVA代码中调用LzoIndexer。以下代码可以同步处理LZOP文件,同步生成索引文件:

 LzoIndexer lzoIndexer = new LzoIndexer(new Configuration());

 for (String arg: args) {
try {
lzoIndexer.index(new Path(arg));
} catch (IOException e) {
LOG.error("Error indexing " + arg, e);
}
...

通过DistributedLzoIndexer,MapReduce作业将会为每个lzo文件调用一个map任务。不需要reduce任务。Map任务通过自定义的LzoSplitInputFormat和LzoIndexOutputFormat可以直接生成索引文件。如果需要自定义调用MapReduce的JAVA代码,可以参考DistributedLzoIndexer的源代码。

通过前面的代码,为LZOP文件生成了相应的索引文件。接下来介绍如何在MapReduce中使用它们。

MAPREDUCE和LZOP

有了LZOP文件和相应的索引文件之后,就可以在MapReduce中处理LZOP文件了。然而,Hadoop中并没有哪个输入格式直接支持LZOP和它的索引文件。这里就需要为LZOP自定义输入格式类。

以下代码展示了如何在MapReduce作业中处理LZOP。代码可以用来处理文本文件压缩后的LZOP文件。

 job.setInputFormatClass(LzoTextInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class);
job.getConfiguration().setBoolean("mapred.output.compress", true);
job.getConfiguration().setClass("mapred.output.compression.codec",
LzopCodec.class, CompressionCodec.class);

另外,压缩map的中间输出也可以提高MapReduce作业的运行速度。代码如下:

 conf.setBoolean("mapred.compress.map.output", true);
conf.setClass("mapred.map.output.compression.codec", LzopCodec.class, CompressionCodec.class);

通过配置集群的hdfs-site.xml文件可以总是压缩map的输出:

 <property>
<name>mapred.compress.map.output</name>
<value>true</value>
</property>
<property>
<name>mapred.map.output.compression.codec</name>
<value>com.hadoop.compression.lzo.LzopCodec</value>
</property>

需要注意的是,LZOP文件中分块的数量是文件占据的LZOP的块的数量,不是文件占据的HDFS块的数量。

接下来介绍如何在Pig和Hive中处理LZOP。

PIG和HIVE

Elephant Bird是Twitter维护的一个项目,包含处理LZOP的工具。它提供了很多有用的MapReduce和Pig类来处理LZOP。Elephant Bird提供了LzoPigStorage来处理Pig中文本文件的LZOP压缩数据。

Hive可以通过com.hadoop.mapred.DeprecatedLzoTextInputFormat这个输入格式来处理文本文件的LZOP压缩文件。这个输入格式类可以在Todd Lipcon和Kevin Weil的LZO项目中找到。

小结

在Hadoop中处理可分块的压缩数据很有技巧性。如果恰好可以直接用SequenceFiles或Avro来处理数据,那么是再简单不过了。如果一定要压缩并分块,那只能用LZOP了。

正如前面提到的,Elephant Bird项目提供了一些有用的LZOP输入格式来处理LZOP的压缩文件,比如说XML和纯文本的压缩文件。如果你需要处理不被Todd Lipcon的LZO项目和Elephant Bird支持的LZOP的压缩文件格式,就需要自定义输入格式。这对大部分人来说相当困难。期望Hadoop可以早日提供对有特别的分块逻辑的压缩文件的支持,减少开发者的负担。

压缩是所有的生产环境所需要的,因为资源永远稀缺。压缩可以加快执行,减少存储空间。在前面一个章节介绍了如何评价并选择合适的编码器。然后介绍了如何在HDFS,MapReduce,Pig和Hive中使用压缩。最后介绍了如何处理LZOP压缩。

[大牛翻译系列]Hadoop(19)MapReduce 文件处理:基于压缩的高效存储(二)的更多相关文章

  1. [大牛翻译系列]Hadoop(18)MapReduce 文件处理:基于压缩的高效存储(一)

    5.2 基于压缩的高效存储 (仅包括技术25,和技术26) 数据压缩可以减小数据的大小,节约空间,提高数据传输的效率.在处理文件中,压缩很重要.在处理Hadoop的文件时,更是如此.为了让Hadoop ...

  2. [大牛翻译系列]Hadoop 翻译文章索引

    原书章节 原书章节题目 翻译文章序号 翻译文章题目 链接 4.1 Joining Hadoop(1) MapReduce 连接:重分区连接(Repartition join) http://www.c ...

  3. [大牛翻译系列]Hadoop(17)MapReduce 文件处理:小文件

    5.1 小文件 大数据这个概念似乎意味着处理GB级乃至更大的文件.实际上大数据可以是大量的小文件.比如说,日志文件通常增长到MB级时就会存档.这一节中将介绍在HDFS中有效地处理小文件的技术. 技术2 ...

  4. [大牛翻译系列]Hadoop(1)MapReduce 连接:重分区连接(Repartition join)

    4.1 连接(Join) 连接是关系运算,可以用于合并关系(relation).对于数据库中的表连接操作,可能已经广为人知了.在MapReduce中,连接可以用于合并两个或多个数据集.例如,用户基本信 ...

  5. [大牛翻译系列]Hadoop(5)MapReduce 排序:次排序(Secondary sort)

    4.2 排序(SORT) 在MapReduce中,排序的目的有两个: MapReduce可以通过排序将Map输出的键分组.然后每组键调用一次reduce. 在某些需要排序的特定场景中,用户可以将作业( ...

  6. [大牛翻译系列]Hadoop(10)MapReduce 性能调优:诊断reduce性能瓶颈

    6.2.3 Reduce的性能问题 Reduce的性能问题有和map类似的方面,也有和map不同的方面.图6.13是reduce任务的具体的执行各阶段,标识了可能影响性能的区域. 这一章将介绍影响re ...

  7. [大牛翻译系列]Hadoop(9)MapReduce 性能调优:理解性能瓶颈,诊断map性能瓶颈

    6.2 诊断性能瓶颈 有的时候作业的执行时间会长得惊人.想靠猜也是很难猜对问题在哪.这一章中将介绍如何界定问题,找到根源.涉及的工具中有的是Hadoop自带的,有的是本书提供的. 系统监控和Hadoo ...

  8. [大牛翻译系列]Hadoop(8)MapReduce 性能调优:性能测量(Measuring)

    6.1 测量MapReduce和环境的性能指标 性能调优的基础系统的性能指标和实验数据.依据这些指标和数据,才能找到系统的性能瓶颈.性能指标和实验数据要通过一系列的工具和过程才能得到. 这部分里,将介 ...

  9. [大牛翻译系列]Hadoop(7)MapReduce:抽样(Sampling)

    4.3 抽样(Sampling) 用基于MapReduce的程序来处理TB级的数据集,要花费的时间可能是数以小时计.仅仅是优化代码是很难达到良好的效果. 在开发和调试代码的时候,没有必要处理整个数据集 ...

随机推荐

  1. 请谨慎使用 @weakify 和 @strongify

    来源:酷酷的哀殿 链接:http://www.jianshu.com/p/d8035216b257 前言 相信大部分见过 @weakify 和 @strongify 的开发者都会喜欢上这两个宏.但是很 ...

  2. 将字符转换为unicode码

    将字符转换为unicode码: /** * unicode转义字符 * @param ch * @param out */ public static void unicodeEscape(int c ...

  3. 通过CAGradientLayer类实现色度差动画

    #import "ViewController.h" @interface ViewController () { CAGradientLayer *_gradientLayer; ...

  4. [Oracle] Oracle和SQLServer的数据类型比较

    类型名称 Oracle SQLServer 比较 字符数据类型 CHAR CHAR 都是固定长度字符资料但oracle里面最大度为2kb,SQLServer里面最大长度为8kb 变长字符数据类型 VA ...

  5. centos下 rpm包sphinx安装成功提示

    sphinx: /etc/sphinx /usr/share/sphinx Sphinx installed! Now create a full-text index, start the sear ...

  6. 双系统Linux(ubuntu)进入windows的NTFS分区之挂载错误

    自从装了双系统(ubuntu&win10)后,发现有时在ubuntu下无法进行win磁盘,于是在网上搜了点资料得以解决,并在此记录一下: 问题如下: 解决步骤: 1.ctrl+alt+t打开终 ...

  7. .NET中的Queue和Stack

    1.ArrayList类 ArrayList类主要用于对一个数组中的元素进行各种处理.在ArrayList中主要使用Add.Remove.RemoveAt.Insert四个方法对栈进行操作.Add方法 ...

  8. Python-Networkx

    import networkx #建图 G = networkx.Graph() #节点数: len(G) #边数 G.number_of_edges() #节点表 G.nodes() #边表 G.e ...

  9. C#中的virtual & override

    很奇怪的设计,需要靠着两个Keyword共同作用,才能完成多态——而不是类似Java那样的默认多态.所谓共同作用,即基类使用virtual 标示函数,子类使用override显示重写. 有点奇怪,MS ...

  10. 剑指Offer42 左旋字符串

    /************************************************************************* > File Name: 42_LeftRo ...