[大牛翻译系列]Hadoop(19)MapReduce 文件处理:基于压缩的高效存储(二)
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文件。操作步骤如下:
- 在主机上安装lzop程序。(RedHat和Centos上可以从http://pkgs.repoforge.org/lzop/lzop-1.03-1.el5.rf.x86_64.rpm 安装。)
- 将LZOP文件从HDFS上拷贝到本地磁盘。
- 使用lzop程序解压缩这个LZOP文件。
- 将解压缩后的文件和原始文件进行对比。
操作脚本如下:
$ 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 文件处理:基于压缩的高效存储(二)的更多相关文章
- [大牛翻译系列]Hadoop(18)MapReduce 文件处理:基于压缩的高效存储(一)
5.2 基于压缩的高效存储 (仅包括技术25,和技术26) 数据压缩可以减小数据的大小,节约空间,提高数据传输的效率.在处理文件中,压缩很重要.在处理Hadoop的文件时,更是如此.为了让Hadoop ...
- [大牛翻译系列]Hadoop 翻译文章索引
原书章节 原书章节题目 翻译文章序号 翻译文章题目 链接 4.1 Joining Hadoop(1) MapReduce 连接:重分区连接(Repartition join) http://www.c ...
- [大牛翻译系列]Hadoop(17)MapReduce 文件处理:小文件
5.1 小文件 大数据这个概念似乎意味着处理GB级乃至更大的文件.实际上大数据可以是大量的小文件.比如说,日志文件通常增长到MB级时就会存档.这一节中将介绍在HDFS中有效地处理小文件的技术. 技术2 ...
- [大牛翻译系列]Hadoop(1)MapReduce 连接:重分区连接(Repartition join)
4.1 连接(Join) 连接是关系运算,可以用于合并关系(relation).对于数据库中的表连接操作,可能已经广为人知了.在MapReduce中,连接可以用于合并两个或多个数据集.例如,用户基本信 ...
- [大牛翻译系列]Hadoop(5)MapReduce 排序:次排序(Secondary sort)
4.2 排序(SORT) 在MapReduce中,排序的目的有两个: MapReduce可以通过排序将Map输出的键分组.然后每组键调用一次reduce. 在某些需要排序的特定场景中,用户可以将作业( ...
- [大牛翻译系列]Hadoop(10)MapReduce 性能调优:诊断reduce性能瓶颈
6.2.3 Reduce的性能问题 Reduce的性能问题有和map类似的方面,也有和map不同的方面.图6.13是reduce任务的具体的执行各阶段,标识了可能影响性能的区域. 这一章将介绍影响re ...
- [大牛翻译系列]Hadoop(9)MapReduce 性能调优:理解性能瓶颈,诊断map性能瓶颈
6.2 诊断性能瓶颈 有的时候作业的执行时间会长得惊人.想靠猜也是很难猜对问题在哪.这一章中将介绍如何界定问题,找到根源.涉及的工具中有的是Hadoop自带的,有的是本书提供的. 系统监控和Hadoo ...
- [大牛翻译系列]Hadoop(8)MapReduce 性能调优:性能测量(Measuring)
6.1 测量MapReduce和环境的性能指标 性能调优的基础系统的性能指标和实验数据.依据这些指标和数据,才能找到系统的性能瓶颈.性能指标和实验数据要通过一系列的工具和过程才能得到. 这部分里,将介 ...
- [大牛翻译系列]Hadoop(7)MapReduce:抽样(Sampling)
4.3 抽样(Sampling) 用基于MapReduce的程序来处理TB级的数据集,要花费的时间可能是数以小时计.仅仅是优化代码是很难达到良好的效果. 在开发和调试代码的时候,没有必要处理整个数据集 ...
随机推荐
- Data Struture 之 指针
指针是C语言中广泛使用的一种数据类型. 运用指针编程是C语言最主要的风格之一.利用指针变量可以表示各种数据结构: 能很方便地使用数组和字符串: 并能象汇编语言一样处理内存地址,从而编出精练而高效的程 ...
- 1.4.2 solr字段类型--(1.4.2.5)使用枚举字段
1.4.2 solr字段类型 (1.4.2.1) 字段类型定义和字段类型属性. (1.4.2.2) solr附带的字段类型 (1.4.2.3) 使用货币和汇率 (1.4.2.4) 使用Dates(日期 ...
- SQL 必知必会-- 第1课:数据库基础和什么是SQL
第1课 了解SQL 1 1.1 数据库基础 11.2 什么是SQL 61.3 动手实践 71.4 小结 8 第一课主要是一些概念,具体笔记如下: 1,数据库(database):保存有组织的数据的容器 ...
- Android小项目之十二 设置中心的界面
------- 源自梦想.永远是你IT事业的好友.只是勇敢地说出我学到! ---------- 按惯例,写在前面的:可能在学习Android的过程中,大家会和我一样,学习过大量的基础知识,很多的知识点 ...
- cocoapods 卸载,重装,高版本的使用
今天清理下电脑,发现自己电脑上的cocoapods经常出现的一个问题就是一些经常用的第三方库cocoapods搜不到,比如SDWebImage,然后就鼓捣了一下 $pos list 命令发现M 以后的 ...
- Java Script基础(三) 函数
一.JavaScript中的函数 在JavaScript中,函数类似于Java中的方法,是执行特定功能的代码块,可以重复调用.JavaScript中的函数分为两种,一种是系统函数,另一种是自定义函数. ...
- 控制语句(if-else+循环+switch)汇编规则
[1]说说条件码 最常用的的条件码有: CF:进位标志 (无符号溢出) ZF:零标志 SF:符号标志(结果为负数) OF:溢出标志 (补码溢出, 有符号溢出) [2]有两类指令设置条件码而不改变任何其 ...
- Table of Contents - CXF
Getting Started A simple JAX-WS service Writing a service with Spring Tools WSDL to Java RESTful Ser ...
- asp动态生成google的sitemap地图的代码
本来使用那些网站生成google网站地图,时间久了,感觉太麻烦了:先打开他们的网站,输入我的网址,然后点击生成,等待一段时间后,下载生成后的文件,再将它通过ftp上传到空间上了.实在太麻烦了,还不如自 ...
- MySQL之建设工程监管信息系统
--创建SelfStudy数据库 CREATE DATABASE ConstructionDB ON PRIMARY --创建主数据库文件 ( NAME=' ConstructionDB', --数据 ...