打怪升级之小白的大数据之旅(五十七)

Hadoop压缩

上次回顾

介绍完zookeeper之后,接下来就是Hadoop的扩展知识点,压缩和HA了,因为HA是建立在zookeeper基础上的,所以我现在才带来这个知识点

Hadoop压缩

压缩概述

  • 首先我们要知道,压缩是一种对数据的优化方法
  • 使用压缩可以有效减少HDFS存储数据的读写字节数,提高网络带宽和磁盘空间的使用效率
  • 因为运行MR操作时,Shuffle和Merge要花费大量的时间,所以使用压缩可以提高我们MR程序的工作效率

压缩的优缺点

  • 虽然通过对MR过程中的数据进行压缩可以减少磁盘IO来提高MR程序运行速度,但压缩同时增加了CPU的运算负担
  • 因为压缩后的数据需要解压缩才可以使用,所以压缩特效运用得当可以提高性能,运用不当也可能降低性能

使用压缩的场景

了解了压缩的优缺点,我们自然就可以猜到压缩的应用场景了吧?

  • 运算密集型的任务(job),我们尽量少用压缩
  • IO密集型的任务(job),我们要多用压缩

MR的压缩编码

  • 压缩也分为很多种格式,因为它们的底层算法不同
  • 通过不同的压缩技术,我们可以针对不同的场景来使用压缩
  • 下面,让我们来了解一下MR支持的几种压缩技术

MR支持的压缩编码

压缩格式

hadoop自带?

算法

文件扩展名

是否可切分

换成压缩格式后,原来的程序是否需要修改

DEFLATE

是,直接使用

DEFLATE

.deflate


和文本处理一样,不需要修改

Gzip

是,直接使用

DEFLATE

.gz


和文本处理一样,不需要修改

bzip2

是,直接使用

bzip2

.bz2


和文本处理一样,不需要修改

LZO

否,需要安装

LZO

.lzo


需要建索引,还需要指定输入格式

Snappy

否,需要安装

Snappy

.snappy


和文本处理一样,不需要修改

Hadoop的编码/解码API

压缩格式

对应的编码/解码器

DEFLATE

org.apache.hadoop.io.compress.DefaultCodec

gzip

org.apache.hadoop.io.compress.GzipCodec

bzip2

org.apache.hadoop.io.compress.BZip2Codec

LZO

com.hadoop.compression.lzo.LzopCodec

Snappy

org.apache.hadoop.io.compress.SnappyCodec

压缩性能比较

压缩算法

原始文件大小

压缩文件大小

压缩速度

解压速度

gzip

8.3GB

1.8GB

17.5MB/s

58MB/s

bzip2

8.3GB

1.1GB

2.4MB/s

9.5MB/s

LZO

8.3GB

2.9GB

49.3MB/s

74.6MB/s

snappy

8.3GB

4GB

250MB/s

500MB/s

snappy的压缩速度是最快的,但是它的压缩效果是最低的,基本上只能将文件压缩至源文件的一半大小左右,想要了解snappy的小伙伴可以参考github的说明:http://google.github.io/snappy

压缩参数配置

参数

默认值

阶段

建议

io.compression.codecs (在core-site.xml中配置

org.apache.hadoop.io.compress.DefaultCodecorg.apache.hadoop.io.compress.GzipCodecorg.apache.hadoop.io.compress.BZip2Codec

输入压缩

Hadoop使用文件扩展名判断是否支持某种编解码器

mapreduce.map.output.compress(在mapred-site.xml中配置)

false

mapper输出

这个参数设为true启用压缩

mapreduce.map.output.compress.codec(在mapred-site.xml中配置)

org.apache.hadoop.io.compress.DefaultCodec

mapper输出

企业多使用LZO或Snappy编解码器在此阶段压缩数据

mapreduce.output.fileoutputformat.compress(在mapred-site.xml中配置)

false

reducer输出

这个参数设为true启用压缩

mapreduce.output.fileoutputformat.compress.codec(在mapred-site.xml中配置)

org.apache.hadoop.io.compress.DefaultCodec

reducer输出

使用标准工具或者编解码器,如gzip和bzip2

表格是为了让大家方便查看,下面来总结一下压缩应用场景

  • Gzip
  • Hadoop本身支持,使用方便,因为在程序中处理Gzip格式的文件就和直接处理文本一样,并且大部分的linux系统都有Gzip命令
  • 因为Gzip不支持切片,所以当单个文件压缩的大小约等于一个块以内(130M左右),我们可以采用Gzip
  • Bzip2
  • Bzip2同样是Hadoop自带的一种压缩格式,它的特点是支持对单个很大的文本文件压缩时又想对其进行切片,此时我们就选择使用Bzip
  • 但是Bzip2的压缩、解压缩的速度比较慢
  • Lzo
  • 压缩、解压缩速度块,支持切片,是我们最常使用的压缩格式之一,我们可以在Linux中安装lzop命令来使用它
  • Lzo在使用的时候需要对Lzo格式文件做一些特殊处理,比如为了支持切片,我们需要建立索引,并且指定InputFormat为Lzo格式
  • Lzo的特点是压缩后数据量大小还大于200M的时候使用
  • Lzo最大的优势就是单个文件越大,它的压缩效率优势就越明显
  • Snappy
  • 它的特点就一个字,快,高速的压缩、解压缩效率,让其他压缩望尘莫及
  • 但是它不支持切片并且压缩后的大小是源文件的一半
  • 正因为它很快,所以我们通常在MR的Map阶段数据比较大的时候作为Map到Reduce的中间格式,或者作为一个MR作业输出到另一个MR作业输入的时候使用

数据流的压缩和解压缩

  • 了解了压缩和解压缩以及MR支持的格式之后,下面我们通过代码来演示具体压缩是怎么创建使用的
  • 在Hadoop中,我们可以使用内置的CompressionCodec对象来创建压缩流完成对文件的压缩、解压缩
package com.compress;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.compress.*;
import org.apache.hadoop.util.ReflectionUtils;
import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class CompressDemo {
    /**
     *  压缩
     */
    @Test
    public void test() throws Exception {
        //1.输入流--普通文件流
        FileInputStream fis = new FileInputStream("D:\\io\\compress\\aaa.txt");


        //2.输出流--压缩流
        //2.1创建对应的编解码器的对象
        CompressionCodec gzipCodec =
                ReflectionUtils.newInstance(GzipCodec.class, new Configuration());
        //2.2创建流
        //gzipCodec.getDefaultExtension() : 获取压缩类型的扩展名
        CompressionOutputStream cos = gzipCodec.createOutputStream(
                new FileOutputStream("D:\\io\\decompress\\aaa.txt" +
                        gzipCodec.getDefaultExtension()));

        //3.文件对拷
        IOUtils.copyBytes(fis,cos,1024,true);

    }


    /**
     * 解压缩
     */
    @Test
    public void test2() throws Exception {
        //输入流---压缩流
        CompressionCodec gzipCodec =
                ReflectionUtils.newInstance(GzipCodec.class, new Configuration());
        CompressionInputStream cis = gzipCodec.createInputStream(
                new FileInputStream("D:\\io\\decompress\\aaa.txt.gz"));

        //输出流---普通的文件流
        FileOutputStream fos = new FileOutputStream("D:\\io\\compress\\aaa.txt");

        //3.文件对拷
        IOUtils.copyBytes(cis,fos,1024,true);
    }


    /**
     * 解压缩
     */
    @Test
    public void test3() throws Exception {
        //创建压缩的工厂类
        CompressionCodecFactory factory = new CompressionCodecFactory(new Configuration());

        //输入流---压缩流
        //根据文件的扩展名创建对应的编解码器类的对象(智能)
        CompressionCodec gzipCodec =
                factory.getCodec(new Path("D:\\io\\decompress\\aaa.txt.gz"));

        if (gzipCodec != null){//没有对应的编解码器的对象

            CompressionInputStream cis = gzipCodec.createInputStream(
                    new FileInputStream("D:\\io\\decompress\\aaa.txt.gz"));

            //输出流---普通的文件流
            FileOutputStream fos = new FileOutputStream("D:\\io\\compress\\aaa.txt");

            //3.文件对拷
            IOUtils.copyBytes(cis,fos,1024,true);
        }


    }

}

总结

本章对压缩的知识点进行分享,了解并使用压缩是在我们日常工作中必不可少的知识之一,合理的使用压缩可以大大提高我们程序的执行效率,好了,本章内容就是这些,下一章为大家带来Hadoop的HA