想想一下,当你须要处理500TB的数据的时候,你最先要做的是存储下来。

你是选择源文件存储呢?还是处理压缩再存储?非常显然,压缩编码处理是必须的。一段刚刚捕获的60分钟原始视屏可能达到2G,经过压缩处理能够减至500MB左右。一张单反照片可能有5MB。经过压缩之后仅仅有400KB,而质量不会发生明显的损失。


hadoop面临的情况也是一样的,大量的数据须要存储在磁盘或者内存中,进行压缩是一种经济的方法。对数据文件进行压缩,能够有效降低存储文件所需的空间,并加快数据在网络上或者到磁盘上的传输速度。

在Hadoop中。压缩应用于文件存储、Map阶段到Reduce阶段的数据交换(须要打开相关的选项)等情景。

数据压缩的方式许多。不同特点的数据有不同的数据压缩方式:如对声音和图像等特殊数据的压缩,就能够採用有损的压缩方法,同意压缩过程中损失一定的信 息,换取比較大的压缩比。而对音乐数据的压缩,因为数据有自己比較特殊的编码方式,因此也能够採用一些针对这些特殊编码的专用数据压缩算法。

hadoop使用的压缩工具主要有:

压缩格式 工具 算法 扩展名 多文件 可切割性
DEFLATE DEFLATE .deflate
GZIP gzip DEFLATE .gzp
ZIP zip DEFLATE .zip 是,在文件范围内
BZIP2 bzip2 BZIP2 .bz2
LZO lzop LZO .lzo


hadoop使用的编码器:



考察压缩工具的性能,主要从时间和空间考虑。一个压缩工具,压缩相同的文件。花费的时间越短。空间越少。压缩率越大,我们就会越喜欢他。

另外还要考虑的就是可不可以切割文件。在hadoop中不可以切割文件是个不好的消息。

由于hadoop处理数据进行计算的时候,须要将大量的大文件拆分,切割就非常重要了。


哪个性能好呢?(以下表格数据引自IBM

压缩算法 原始文件大小 压缩文件大小 压缩速度 解压速度
gzip 8.3GB 1.8GB 17.5MB/s 58MB/s
bzip2 8.3GB 1.1GB 2.4MB/s 9.5MB/s
LZO-bset 8.3GB 2GB 4MB/s 60.6MB/s
LZO 8.3GB 2.9GB 49.3MB/s 74.6MB/s

这还不是所有。hadoop通过压缩流,也就是将文件写进压缩流里面进行数据读写,性能怎样呢?




下面引自xuxm2007

CompressionCodec对流进行压缩和解压缩
CompressionCodec有两个方法能够用于轻松地压缩或解压缩数据。

要想对正在被写入一个输出流的数据进行压缩。我们能够使用 createOutputStream(OutputStreamout)方法创建一个CompressionOutputStream(未压缩的数据将 被写到此),将其以压缩格式写入底层的流。相反。要想对从输入流读取而来的数据进行解压缩,则调用 createInputStream(InputStreamin)函数,从而获得一个CompressionInputStream,。从而从底层的流
读取未压缩的数据。CompressionOutputStream和CompressionInputStream类似干 java.util.zip.DeflaterOutputStream和java.util.zip.DeflaterInputStream,前两者 还能够提供重置其底层压缩和解压缩功能,当把数据流中的section压缩为单独的块时,这比較重要。比方SequenceFile。

下例中说明了怎样使用API来压缩从标谁输入读取的数据及怎样将它写到标准输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class StreamCompressor 
{
     public static void main(String[] args) throws Exception 
     {
          String codecClassname = args[0];
          Class<?> codecClass = Class.forName(codecClassname); // 通过名称找相应的编码/解码器
          Configuration conf = new Configuration();
CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(codecClass, conf);
 // 通过编码/解码器创建相应的输出流

          CompressionOutputStream out = codec.createOutputStream(System.out);
 // 压缩

          IOUtils.copyBytes(System.in, out, 4096, false);
          out.finish();
     }


用CompressionCodecFactory方法来判断CompressionCodecs

在阅读一个压缩文件时,我们通常能够从其扩展名来判断出它的编码/解码器。以.gz结尾的文件能够用GzipCodec来阅读。如此类推。每一个压缩格式的扩展名如第一个表格;

CompressionCodecFactory提供了getCodec()方法。从而将文件扩展名映射到对应的CompressionCodec。

此方法接受一个Path对象。以下的样例显示了一个应用程序,此程序便使用这个功能来解压缩文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class FileDecompressor {
    public static void main(String[] args) throws Exception {
       String uri = args[0];
       Configuration conf = new Configuration();
       FileSystem fs = FileSystem.get(URI.create(uri), conf);
       Path inputPath = new Path(uri);
       CompressionCodecFactory factory = new CompressionCodecFactory(conf);
       CompressionCodec codec = factory.getCodec(inputPath);
       if (codec == null) {
           System.err.println("No codec found for " + uri);
           System.exit(1);
       }
       String outputUri =
       CompressionCodecFactory.removeSuffix(uri, codec.getDefaultExtension());
       InputStream in null;
       OutputStream out = null;
       try {
           in = codec.createInputStream(fs.open(inputPath));
           out = fs.create(new Path(outputUri));
           IOUtils.copyBytes(in, out, conf);
       } finally {
           IOUtils.closeStream(in);
           IOUtils.closeStream(out);
       }
    }
}

编码/解码器一旦找到,就会被用来去掉文件名称后缀生成输出文件名称(通过CompressionCodecFactory的静态方法removeSuffix()来实现)。这样,例如以下调用程序便把一个名为file.gz的文件解压缩为file文件:

% hadoop FileDecompressor file.gz

CompressionCodecFactory 从io.compression.codecs配置属性定义的列表中找到编码/解码器。默认情况下。这个列表列出了Hadoop提供的全部编码/解码器 (见表4-3),假设你有一个希望要注冊的编码/解码器(如外部托管的LZO编码/解码器)你能够改变这个列表。每一个编码/解码器知道它的默认文件扩展
名,从而使CompressionCodecFactory能够通过搜索这个列表来找到一个给定的扩展名相匹配的编码/解码器(假设有的话)。

 属性名  类型  默认值  描写叙述
io.compression.codecs 逗号分隔的类名 org.apache.hadoop.io.compress.DefaultCodec,

org.apache.hadoop.io.compress.GzipCodec,

org.apache.hadoop.io.compress.Bzip2Codec
用于压缩/解压的CompressionCodec列表

本地库

考虑到性能,最好使用一个本地库(native library)来压缩和解压。

比如,在一个測试中,使用本地gzip压缩库降低了解压时间50%,压缩时间大约降低了10%(与内置的Java实现相比 较)。表4-4展示了Java和本地提供的每一个压缩格式的实现。井不是全部的格式都有本地实现(比如bzip2压缩)。而还有一些则仅有本地实现(比如 LZO)。

压缩格式 Java实现 本地实现
DEFLATE
gzip
bzip2
LZO

Hadoop带有预置的32位和64位Linux的本地压缩库,位于库/本地文件夹。对于其它平台,须要自己编译库,详细请參见Hadoop的维基百科http://wiki.apache.org/hadoop/NativeHadoop。

本地库通过Java系统属性java.library.path来使用。Hadoop的脚本在bin文件夹中已经设置好这个属性。但假设不使用该脚本,则须要在应用中设置属性。

默认情况下,Hadoop会在它执行的平台上查找本地库,假设发现就自己主动载入。这意味着不必更改不论什么配置设置就能够使用本地库。在某些情况下,可能 希望禁用本地库,比方在调试压缩相关问题的时候。为此。将属性hadoop.native.lib设置为false,就可以确保内置的Java等同内置实现 被使用(假设它们可用的话)。

CodecPool(压缩解码池)

假设要用本地库在应用中大量运行压缩解压任务。能够考虑使用CodecPool,从而重用压缩程序和解压缩程序,节约创建这些对象的开销。

下例所用的API仅仅创建了一个非常easy的压缩程序。因此不必使用这个池。此应用程序使用一个压缩池程序来压缩从标准输入读入然后将其写入标准愉出的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class PooledStreamCompressor 
 {
    public static void main(String[] args) throws Exception 
    {
        String codecClassname = args[0];
        Class<?

> codecClass = Class.forName(codecClassname);

        Configuration conf = new Configuration();
CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(codecClass, conf);
        Compressor compressor = null;
        try {
compressor = CodecPool.getCompressor(codec);//从缓冲池中为指定的CompressionCodec检索到一个Compressor实例
CompressionOutputStream out = codec.createOutputStream(System.out, compressor);
            IOUtils.copyBytes(System.in, out, 4096, false);
            out.finish();
        } finally
        {
            CodecPool.returnCompressor(compressor);
        }
      }

我 们从缓冲池中为指定的CompressionCodec检索到一个Compressor实例,codec的重载方法 createOutputStream()中使用的便是它。通过使用finally块,我们便可确保此压缩程序会被返回缓冲池,即使在复制数据流之间的字 节期间抛出了一个IOException。
压缩和输入切割

在考虑怎样压缩那些将由MapReduce处理的数据时,考虑压缩格式是否支持切割是非常重要的。考虑存储在HDFS中的未压缩的文件,其大小为1GB. HDFS块的大小为64MB ,所以文件将被存储为16块,将此文件用作输入的MapReduce会创建16个输入分片(split。也称为"分块"),每一个分片都被作为一个独立map任务的输入单独进行处理。

如今如果,该文件是一个gzip格式的压缩文件,压缩后的大小为1GB。和前面一样。HDFS将此文件存储为 16块。然而,针对每一块创建一个分块是没实用的由于不可能从gzip数据流中的随意点開始读取,map任务也不可能独立于其分块仅仅读取一个分块中的数据。gZlp格式使用DEFLATE来存储压缩过的数据。DEFLATE
将数据作为一系列压缩过的块进行存储。问题是,每块的開始没有指定用户在数据流中随意点定位到下一个块的起始位置,而是其自身与数据流同步。

因此,gzip不支持切割(块)机制。在这样的情况下,MapReduce不切割gzip格式的文件,由于它知道输入的是gzip格式(通过文件扩展名得知),而gzip压缩机制不支持切割机制。这样是以牺牲本地化为代价:一个map任务将处理16个HDFS块,大都不是map的本地数据。与此同一时候,由于map任务少,所以作业切割的粒度不够细,从而导致执行时间变长。


在我们如果的样例中,如果是一个LZO格式的文件,我们会碰到相同的问题,因为基本压缩格式不为reader 提供方法使其与流同步。

可是,bzip2格式的压缩文件确实提供了块与块之间的同步标记(一个48位的π近似值) 因此它支持切割机制。

对于文件的收集。这些问题会稍有不同。ZIP是存档格式,因此t能够将多个文件合并为一个ZIP文件。每一个文单独压缩。全部文档的存储位置存储在ZIP文件的尾部。这个属性表明Z l P 文件支持文件边界处切割,每一个分片中包含ZIP压缩文件中的一个或多个文件。


ZIP格式文件的结构例如以下图:ZIP文件结构请查看wiki



在MapReduce 中使用压缩

如前所述,假设输入的文件是压缩过的.那么在被MapReduce 读取时,它们会被自己主动解压。依据文件扩展名来决定应该使用哪一个压缩解码器。假设要压缩MapReduce作业的输出.请在作业配置文件里将mapred.output.compress属性设置为true,将mapred.output.compression.codec属性设置为自己打算使用的压缩编码/解码器的类名。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    public class MaxTemperatureWithCompression {
 
        public static void main(String[] args) throws Exception {
            if (args.length != 2) {
                System.err.println("Usage: MaxTemperatureWithCompression <input path> "
                        "<output path>");
                System.exit(-1);
            }
            Job job = new Job();
            job.setJarByClass(MaxTemperature.class);
            FileInputFormat.addInputPath(job, new Path(args[0]));
            FileOutputFormat.setOutputPath(job, new Path(args[1]));
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(IntWritable.class);
            FileOutputFormat.setCompressOutput(job, true);
            FileOutputFormat.setOutputCompressorClass(job, GzipCodec.class);
            job.setMapperClass(MaxTemperatureMapper.class);
            job.setCombinerClass(MaxTemperatureReducer.class);
            job.setReducerClass(MaxTemperatureReducer.class);
            System.exit(job.waitForCompletion(true) ? 0 1);
        }
    }

我们使用压缩过的输入来执行此应用程序(事实上不必像它一样使用和输入同样的格式压缩输出),例如以下所看到的:
% hadoop MaxTemperatur eWithCompression input/ ncdc/sample.txt.gz
output
量生终输出的每部分都是压缩过的.在本例中。仅仅有一部分:
% gunzip -c output/part-OOOOO.gz
1949 111
1950 22
假设为输出使用了一系列文件, 能够设置mapred.output.compresson.type 属性来控制压缩类型。默觉得RECORD,它压缩单独的记录。将它改为BLOCK,可以压缩一组记录,因为有更好的压缩比。所以推荐使用。

map 作业输出结果的压缩
即使MapReduce 应用使用非压缩的数据来读取和写入,我们也能够受益于压缩map阶段的中阔输出。由于map作业的输出会被写入磁盘并通过网络传输到reducer节点,所以假设使用LZO之类的高速压缩,能得到更好的性能,由于传输的数据量大大降低了.表4-5显示了启用map输出压缩和设置压缩格式的配置属性.

以下几行代码用于在map 作业中启用gzi p 格式来压缩输出结果:
1
2
3
4
5
Configuration conf = new Configuration();
conf.setBoolean("mapred.compress.map.output"true);
conf.setClass("mapred.map.output.compression.codec", GzipCodec.class,
CompressionCodec.class);
Job job = new Job(conf);

旧的API要这样配置

1
2
conf.setCompressMapOutput(true);
conf.setMapOutputCompressorClass(GzipCodec.class);

压缩就到此为止了。总之编码和解码在hadoop有着关键的作用。

Charles 于P.P 



版权说明:
本文由Charles Dong原创,本人支持开源以及免费故意的传播。反对商业化谋利。
CSDN博客:http://blog.csdn.net/mrcharles
个人站:http://blog.xingbod.cn
EMAIL:charles@xingbod.cn

Hadoop编码解码【压缩解压缩】机制具体解释(1)的更多相关文章

  1. Hadoop编码解码【压缩解压缩】机制详解(1)

    想想一下,当你需要处理500TB的数据的时候,你最先要做的是存储下来.你是选择源文件存储呢?还是处理压缩再存储?很显然,压缩编码处理是必须的.一段刚刚捕获的60分钟原始视屏可能达到2G,经过压缩处理可 ...

  2. Huffman编码实现压缩解压缩

    这是我们的课程中布置的作业.找一些资料将作业完毕,顺便将其写到博客,以后看起来也方便. 原理介绍 什么是Huffman压缩 Huffman( 哈夫曼 ) 算法在上世纪五十年代初提出来了,它是一种无损压 ...

  3. Linux,unix,cygwin,centeros下的tar压缩解压缩命令具体解释

    tar Examples:   tar -cf archive.tar foo bar  # Create archive.tar from files foo and bar.   tar -tvf ...

  4. Python3编码解码url

    python2和python3对于url的解码和编码 某天做爬虫时遇到一个post请求的参数是编码过的字符串如下,看不懂,初步判断可能是url编码 str = "%7B%22Shopping ...

  5. Hadoop案例(二)压缩解压缩

    压缩/解压缩案例 一. 对数据流的压缩和解压缩 CompressionCodec有两个方法可以用于轻松地压缩或解压缩数据.要想对正在被写入一个输出流的数据进行压缩,我们可以使用createOutput ...

  6. Delphi Base64编码/解码及ZLib压缩/解压

    最近在写的程序与SOAP相关,所以用到了一些Base64编码/解码及数据压缩/解压方面的知识. 在这里来作一些总结:   一.Base64编码/解码   一般用到的是Delphi自带的单元EncdDe ...

  7. hadoop的压缩解压缩,reduce端join,map端join

    hadoop的压缩解压缩 hadoop对于常见的几种压缩算法对于我们的mapreduce都是内置支持,不需要我们关心.经过map之后,数据会产生输出经过shuffle,这个时候的shuffle过程特别 ...

  8. 【13】MD5编码、Zlib压缩解压缩

    1.MD5加密 /// <summary> /// 使用MD5加密算法 /// </summary> /// <param name="md5MessageSt ...

  9. Hadoop| YARN| 计数器| 压缩| 调优

    1. 计数器应用 2. 数据清洗(ETL) 在运行核心业务MapReduce程序之前,往往要先对数据进行清洗,清理掉不符合用户要求的数据.清理的过程往往只需要运行Mapper程序,不需要运行Reduc ...

随机推荐

  1. MySQL中in子查询会导致无法使用索引问题(转)

    MySQL的测试环境 测试表如下 create table test_table2 ( id int auto_increment primary key, pay_id int, pay_time ...

  2. P2P通信标准协议(三)之ICE

    在P2P通信标准协议(二)中,介绍了TURN的基本交互流程,在上篇结束部分也有说到,TURN作为STUN 协议的一个拓展,保持了STUN的工具性质,而不作为完整的NAT传输解决方案,只提供穿透NAT的 ...

  3. How To Use NSOperations and NSOperationQueues

    Update 10/7/14: This tutorial has now been updated for iOS 8 and Swift; check it out! Everyone has h ...

  4. What is Mocking?

    Mocking is primarily used in unit testing. An object under test may have dependencies on other (comp ...

  5. espresso 元素遮挡问题。

    在使用espresso进行测试的时候,点击一个横向列表的时候会在点击的项目下出现对应的横线. 实现方式是在FrameLayout下放两个TextView, 一个TextView包含下划线,默认是Fra ...

  6. android intent 跳转

    转自:http://blog.sina.com.cn/s/blog_7309444701014u2d.html 一.不需要返回值的跳转 Intent intent=new Intent(); inte ...

  7. 面试题:Add Two Numbers(模拟单链表)

    题干: You are given two non-empty linked lists representing two non-negative integers. The digits are ...

  8. Javascript modules--js 模块化

    https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc 这个网站也是非常好:https:/ ...

  9. 性能测试篇 :Jmeter监控服务器性能

    转载:http://www.cnblogs.com/chengtch/p/6079262.html jmeter也可以像loadrunner一样监控服务器CPU.内存等性能参数,不过需要安装一些插件 ...

  10. AngularJS, Ember.js, Backbone这类新框架与 jQuery的重要区别在哪里?

    jQuery主要是用来操作DOM的,如果单单说jQuery的话就是这样一个功能,它的插件也比较多,大家也都各自专注一个功能,可以说jQuery体系是跟着前端页面从静态到动态崛起的一个产物,他的作用就是 ...