Hadoop之MapReduce

1.MapReduce定义:
MapReduce是一个分布式运算程序的编程框架,是用户开发"基于hadoop的数据分析应用"的核心框架.
MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组建整合成一个完整的分布式运算程序,并发运行在一个hadoop集群上.
2.MapReduce优缺点:
优点:
1.MapReduce易于编程:
它简单的实现一些接口,就可以完成分布式程序,这个分布式程序可以分布到大量的廉价的pc机器上运行.
2.良好的扩展性:
当你的计算机资源不能得到满足的时候,你可以通过简单的增加机器来扩展它的计算能力
3.高容错性
MapReduce设计的初衷就是使程序能够部署在廉价的pc机器上,这就要求它具有很高的容错性.比如其中一台机器挂了,他可以把上面的计算任务转移到另外一个节点运行,不至于这个任务失败,而这个过程不需要人工参与,而完全由hadoop内部完成的
4.适合PB级以上的海量数据的离线处理
缺点:
1.不擅长实时计算
2.不擅长流式计算:MapReduce的输入数据集是静态的
3.不擅长DAG(有向图)计算

3.MapReduce核心思想:
1)分布式的运算程序往往需要分成至少2个阶段.
2)第一个阶段的MapTask并发实例,完全并行运行,互不相干.
3)第二个阶段的ReduceTask并发实例互不相干,但是他们的数据依赖于上一个阶段的所有MapTask并发实例的输出.
4)MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行.
总结:分析WordCount数据流走向深入理解MapReduce核心思想

4.MapReduce进程:
一个完整的MapReduce程序在分布式运行时有三类实例进程:
1)MrAppMaster:负责整个程序的过程调度及状态协调
2)MapTask:负责Map阶段的整个数据处理流程
3)ReduceTask:负责Reduce阶段的整个数据处理流程

5.常用数据序列化类型

Java类型Hadoop Writable 类型
BooleanBooleanWritable
ByteByteWritable
IntIntWritable
FloatFloatWritable
LongLongWritable
DoubleDoubleWritable
StringText
MapMapWritable
ArrayArrayWritable

6.MapReduce编程规范
用户编写的程序分成三个部分:Mapper,Reducer和Driver.

7.hadoop序列化
1.什么是序列化
序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储到磁盘和网络传输.
反序列化就是将收到字节序列(或其他数据传输协议)或者是磁盘的持久化数据,转换成内存中的对象.

2.为什么要序列化
一般来说,"活的"对象只生存在内存里,关机断电就没有了.而且"活的"对象只能由本地的进程使用,不能被发送到网络上的另外一台计算机.然而序列化可以存储"活的对象,可以将"活的"对象发送到远程计算机.

序列化特点:
(1)紧凑:高效使用存储空间
(2)快速:读写数据的额外开销小
(3)可扩展:随着通信协议的升级而升级
(4)互操作:支持多语言的交互

8.WordCount案例实操
1.创建一个Maven项目
2.在 pom.xml文件中添加依赖

<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>2.8.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-common</artifactId>
			<version>2.7.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-client</artifactId>
			<version>2.7.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-hdfs</artifactId>
			<version>2.7.2</version>
		</dependency>
</dependencies>

3.在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入

log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

4.编写程序
(1)编写Mapper类

package com.jinghang.wordcount;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

/*
* KEYIN, hadoop处理文本后输入到mapper中key值
* VALUEIN,hadoop处理文本后输入到mapper中value值
* KEYOUT,mapper处理文本后输入到context(reducer)中key值
* VALUEOUT,mapper处理文本后输入到context(reducer)中value值
*
* */

/**
 * extends Mapper:继承mapper类
 * LongWritable:文本每一行偏移量的数据类型
 * Text:文本每一行数据的数据类型
 * Text: mapper处理文本后输入到context(reducer)中key值的数据类型
 * IntWritable:mapper处理文本后输入到context(reducer)中value值的数据类型
 */
public class WcMapper extends Mapper<LongWritable, Text,Text, IntWritable> {
    //创建text对象
    private Text keyout = new Text();
    //创建intwritable对象,赋值为1
    private  IntWritable valueout = new IntWritable(1);

    //继承mapper类实现map方法
    //key: 每一行的偏移量
    //value:每一行的文本内容
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        //获取文本的每一行内容
        String line = value.toString();
        //设置分割符
        String[] words = line.split(" ");

        //遍历统计单词个数
        for (String word : words) {
            //将字符串赋值给keyout
            keyout.set(word);
            //输出key,value
            context.write(keyout,valueout);
        }
    }
}

(2)编写Reducer类

package com.jinghang.wordcount;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/*
 * KEYIN, mapper处理文本后输入到context(reducer)中key值
 * VALUEIN,mapper处理文本后输入到context(reducer)中value值
 * KEYOUT,reducer处理文本后输入到context中key值
 * VALUEOUT,reducer处理文本后输入到context中value值
 *
 * */

/**
 * Text,  mapper处理文本后输入到context(reducer)中key值的数据类型
 * IntWritable,mapper处理文本后输入到context(reducer)中value值的数据类型
 * Text,reducer处理文本后输入到context中key值的数据类型
 * IntWritable:reducer处理文本后输入到context中value值的数据类型
 */
public class WcReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
    //创建对象,统计单词出现次数
    private IntWritable total = new IntWritable();

    /**
     * 继承reducer类实现的reduce方法
     * @param key:  mapper处理文本输出的内容
     * @param values:   装的是一组数据
     * @param context:上下文   输出key value
     * @throws IOException  抛出的异常
     * @throws InterruptedException
     */
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        //业务逻辑: 统计单词出现的次数
        int sum = 0;
        //数据进入reducer会根据key组分组,我们在reduce获取的是一组数据
        //通过循环累加,得到某个单词出现的次数
        for (IntWritable value : values) {
            sum=sum+value.get();
        }
        //赋值
        total.set(sum);
        //reducer输出key,value
        context.write(key,total);
    }
}

(3)编写Driver类

package com.jinghang.wordcount;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

public class WcDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        //获取job对象和配置文件对象
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);

        //设置切片处理多个小文件
        job.setInputFormatClass(CombineTextInputFormat.class);
        CombineTextInputFormat.setMaxInputSplitSize(job,4194304);
        //添加jar的路径
        job.setJarByClass(WcDriver.class);

        //设置mapper类和reducer类
        job.setMapperClass(WcMapper.class);
        job.setReducerClass(WcReducer.class);

        // 设置mapper类输出的数据类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        //combiner汇总
        job.setCombinerClass(ComBine.class);

        //设置reducer类输出的数据类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

//        FileInputFormat.setInputPaths(job, new Path("C:\\Users\\dell\\Desktop\\datas\\wcinput"));
//        FileOutputFormat.setOutputPath(job,new Path("C:\\Users\\dell\\Desktop\\datas\\wcoutput"));
        //设置输入出路径
        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job,new Path(args[1]));

        //提交任务
        boolean result = job.waitForCompletion(true);
        //成功返回0,失败返回1
        System.exit(result ? 0:1);
    }
}

9.MapReduce框架原理
InputFormat数据输入

10.切片与MapTask并行度决定机制
1.问题引出
MapTask的并行度决定Map阶段的任务处理并发度,进而影响到整个Job的处理速度
思考:1G的数据,启动8个MapTask,可以提高集群的并发处理能力。那么1K的数据,也启动8个MapTask,会提高集群性能吗?MapTask并行任务是否越多越好呢?哪些因素影响了MapTask并行度?

2.MapTask并行度决定机制
数据块:Block是HDFS物理上把数据分成一块一块.
数据切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储.
在这里插入图片描述

11.FileInputFormat切片机制
(1)简单的按照文件的内容长度进行切片
(2)切片大小,默认等于Block大小
(3)切片时不考虑数据集整体,而是逐个针对每一个文件单独切片

12.CombineTextInputFormat切片机制
框架默认的TextInputFormat切片机制是对任务按文件规划切片,不管文件多小,都会是一个单独的切片,都会交给一个MapTask,这样如果有大量小文件,就会产生大量的MapTask,处理效率极其低下.
1.应用场景:
CombineTextInputFormat用于小文件过多的场景,它可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个MapTask处理.
2.虚拟存储切片最大值设置
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m
注意:虚拟存储切片最大值设置最好根据实际的小文件大小情况来设置具体的值.
3.切片机制
生成切片过程包括:虚拟存储过程和切片过程二部分.
(1)虚拟存储过程:
将输入目录下所有文件大小,依次和设置的setMaxInputSplitSize值比较,如果不大于设置的最大值,逻辑上划分一个块。如果输入文件大于设置的最大值且大于两倍,那么以最大值切割一块;当剩余数据大小超过设置的最大值且不大于最大值2倍,此时将文件均分成2个虚拟存储块(防止出现太小切片)。
例如setMaxInputSplitSize值为4M,输入文件大小为8.02M,则先逻辑上分成一个4M。剩余的大小为4.02M,如果按照4M逻辑划分,就会出现0.02M的小的虚拟存储文件,所以将剩余的4.02M文件切分成(2.01M和2.01M)两个文件。
(2)切片过程:
(a)判断虚拟存储的文件大小是否大于setMaxInputSplitSize值,大于等于则单独形成一个切片。
(b)如果不大于则跟下一个虚拟存储文件进行合并,共同形成一个切片。
(c)测试举例:有4个小文件大小分别为1.7M、5.1M、3.4M以及6.8M这四个小文件,则虚拟存储之后形成6个文件块,大小分别为:
1.7M,(2.55M、2.55M),3.4M以及(3.4M、3.4M)
最终会形成3个切片,大小分别为:
(1.7+2.55)M,(2.55+3.4)M,(3.4+3.4)M

13.FileInputFormat实现类
FileInputFormat常见的接口实现类括:TextInputFormat,KeyValueTextInputFormat,NlineInputFormat,CombineTextInputFormat和自定义InputFormat等.

1.TextInputFormat
TextInputFormat是默认的FileInputFormat实现类, 按行读取每条记录.键是存储该行在整个文件中的起始字节偏移量,LongWritable类型.值是这行的内容,不包含任何终止符(换行符和回车符),Text类型

2.KeyValueTextInputFormat
每一行均为一条记录,被分割符分割为key,value. 可以通过在驱动类中设置conf.set(KeyValueLineRecord.KEY_VALUE_SEPERATOP,"\t")来设定分隔符,默认分隔符是tab,(\t).

14.mr默认的reduceTask数量是多少?mr默认是如何为key,value分配分区的?总结如何自定义分区?使用自定义分区的注意事项(reducetask和分区的关系)?
(1)默认的reduceTask数量为1意味着所有的mapTask处理后的数据都会交给这个reduceTask进行数据的汇总,最终输出一个文件
(2)数据在经过map方法的context.write()写出后,会通过outputcollector收集,底层调用HashPartitioner类的getPartition()方法通过(key.hashCode() & Integer.MAX_VALUE) % numReduceTasks模得到的,但是用户没法控制哪个key存储到哪个分区。
(3)自定义分区首先需要定义一个类,继承自Partitioner,实现getPartition()方法根据具体需求返回对于的分区号,最后通过job.setPartitionerClass()设置分区类
public class FlowPartitioner extends Partitioner<Text,FlowBean> {
public int getPartition(Text text, FlowBean flowBean, int numPartitions) {
//分区号从0开始:5reducetask 5个分区:0~4
//手机号136、137、138、139开头都分别放到一个独立的4个文件中,
//其他开头的放到一个文件中。
String phonenum = text.toString();
switch (phonenum.substring(0,3)){
case “136”:
return 0;
case “137”:
return 1;
case “138”:
return 2;
case “139”:
return 3;
default:
return 4;
}
}
}

(4)注意:
分区号从0开始,不要跳号
当分区数量大于reduceTask数量时,程序运行出错
当设置reduceTask的数量为一时,不走分区方法
当设置的reduceTask数量大于分区时,会产生空的输出文件

15.mapreduce在那些阶段(位置)实现了排序?默认是怎么排序的?如何自定义排序?
(1)MapTask和ReduceTask均会对数据按照key进行排序。MapTask,会将处理的结果暂时放到环形缓冲区中,当环形缓冲区使用率达到一定阈值(100M的百分之80)后,对缓冲区中的数据进行一次快速排序,并将有序数据溢写到磁盘上,最后会对磁盘上所有文件溢写文件进行归并排序.ReduceTask,从每个MapTask上拷贝对应分区的数据文件,如果文件大小超过一定阈值,则溢写磁盘上,否则存储在内存中。当所有数据拷贝完毕后,ReduceTask统一对内存和磁盘上的所有数据进行一次归并排序。
(2)排序操作属于Hadoop的默认行为。任何应用程序中的数据均会被排序,默认排序是按照字典顺序排序,实现该排序的方法是快速排序。
(3)我们需要在数据对象类中实现WritableComparable接口中的 compareTo方法(自然比较方法),从而实现对当前对象和传入对象的比对,实现排序。

16.Combiner是什么有什么作用?Combiner的作用位置和Reducer的作用位置有什么不同?
(1)Combiner是MR程序中Mapper和Reducer之外的一种组件,继承自reducer,是可选的,并不是必须存在的,因为只有在不影响最终业务结果的场景下才能使用。Combiner的作用就是对每一个MapTask的输出进行局部汇总,以减小网络传输量
(2)Combiner是在每一个MapTask所在的节点运行;Reducer是接收全局所有Mapper的输出结果

17.如何实现根据bean对象中的某一个值进行分组?
此场景我们通常使用的是辅助分组,定义类继承自WritableComparator,重写compare()方法通过对象中的某一个或者多个参数比对,参数相同则视为同一组数据进入到reduce方法中。
注意:使用时需要创建一个构造器将比较对象的类传给父类(不然会报出Null…空指针异常)

18.mr处理数据时FileInputFormat中getSplits()方法是如何对数据进行切片的?
默认情况下为了避免mr处理数据的过程中存在网络数据传输,从而降低mr的效率,默认的切片大小为block块大小(128M). FileInputFormat中getSplits()方法会根据文件大小将文件拆分成splits,如果单个文件较小小于128的1.1倍,则每个文件为一个split,并将文件按行分割形成<key,value>对,如果单个文件较大。超过block块(128M)默认大小得1.1倍,则会将文件切分为多个split,切片数量决定了maptask的任务数量.

19.shuffle流程概述?
key,value从map()方法输出后,被outputcollector收集通过HashPartitioner类的getpartitioner()方法获取分区号,进入环形缓冲区。默认情况下,环形缓冲区为100MB。 当环形环形缓冲区存储达到80%,开始执行溢写过程,溢写过程中如果有其他数据进入,那么由剩余的20%反向写入。溢写过程会根据key,value先根据分区进行排序,再根据key值进行排序,后生成一个溢写文件(再对应的分区下根据key值有序),maptask将溢写文件归并排序后落入本地磁盘,reduceTask阶段将多个mapTask下相同分区的数据copy到指定的reduceTask中进行归并排序、分组后一次读取一组数据给reduce()函数.

20.MapTask工作机制
在这里插入图片描述
(1)Read阶段:MapTask通过用户编写的RecordReader,从输入InputSplit中解析出一个个key/value。
(2)Map阶段:该节点主要是将解析出的key/value交给用户编写map()函数处理,并产生一系列新的key/value。
(3)Collect收集阶段:在用户编写map()函数中,当数据处理完成后,一般会调用OutputCollector.collect()输出结果。在该函数内部,它会将生成的key/value分区(调用Partitioner),并写入一个环形内存缓冲区中。
(4)Spill阶段:即“溢写”,当环形缓冲区满后,MapReduce会将数据写到本地磁盘上,生成一个临时文件。需要注意的是,将数据写入本地磁盘之前,先要对数据进行一次本地排序,并在必要时对数据进行合并、压缩等操作。
溢写阶段详情:
步骤1:利用快速排序算法对缓存区内的数据进行排序,排序方式是,先按照分区编号Partition进行排序,然后按照key进行排序。这样,经过排序后,数据以分区为单位聚集在一起,且同一分区内所有数据按照key有序。
步骤2:按照分区编号由小到大依次将每个分区中的数据写入任务工作目录下的临时文件output/spillN.out(N表示当前溢写次数)中。如果用户设置了Combiner,则写入文件之前,对每个分区中的数据进行一次聚集操作。
步骤3:将分区数据的元信息写到内存索引数据结构SpillRecord中,其中每个分区的元信息包括在临时文件中的偏移量、压缩前数据大小和压缩后数据大小。如果当前内存索引大小超过1MB,则将内存索引写到文件output/spillN.out.index中。
(5)Combine阶段:当所有数据处理完成后,MapTask对所有临时文件进行一次合并,以确保最终只会生成一个数据文件。
当所有数据处理完后,MapTask会将所有临时文件合并成一个大文件,并保存到文件output/file.out中,同时生成相应的索引文件output/file.out.index。
在进行文件合并过程中,MapTask以分区为单位进行合并。对于某个分区,它将采用多轮递归合并的方式。每轮合并io.sort.factor(默认10)个文件,并将产生的文件重新加入待合并列表中,对文件排序后,重复以上过程,直到最终得到一个大文件。
让每个MapTask最终只生成一个数据文件,可避免同时打开大量文件和同时读取大量小文件产生的随机读取带来的开销

21. ReduceTask工作机制
在这里插入图片描述
(1)Copy阶段:ReduceTask从各个MapTask上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定阈值,则写到磁盘上,否则直接放到内存中。
(2)Merge阶段:在远程拷贝数据的同时,ReduceTask启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。
(3)Sort阶段:按照MapReduce语义,用户编写reduce()函数输入数据是按key进行聚集的一组数据。为了将key相同的数据聚在一起,Hadoop采用了基于排序的策略。由于各个MapTask已经实现对自己的处理结果进行了局部排序,因此,ReduceTask只需对所有数据进行一次归并排序即可。
(4)Reduce阶段:reduce()函数将计算结果写到HDFS上
2.设置ReduceTask并行度(个数)
ReduceTask的并行度同样影响整个Job的执行并发度和执行效率,但与MapTask的并发数由切片数决定不同,ReduceTask数量的决定是可以直接手动设置:
// 默认值是1,手动设置为4
job.setNumReduceTasks(4)
注意事项:
(1)ReduceTask=0,表示没有Reduce阶段,输出文件个数和Map个数一致
(2)Reduce默认值就是1,所有输出文件个数为一个
(3)如果数据分布不均匀,就有可能在Reduce阶段产生数据倾斜
(4)ReduceTask数量并不是任意设置,还要考虑业务逻辑需求,有些情况下,需要计算全局汇总结果,就只能有一个ReduceTask
(5)具体多少个ReduceTask,需要根据集群性能而定
(6)如果分区数不是1,但ReduceTask为1,是否执行分区过程. 答案是:不执行分区过程.因为在MapTask的源码中,执行分区的前提是先判断ReduceNum个数是否大于1.不大于1肯定不执行.

22.hadoop种的压缩方式有哪些?哪些方式压缩文件支持切片?mr可以在哪些位置执行压缩?
压缩的作用(优点)和原则是什么?默认是否开启了压缩,怎么开启map、reduce端的压缩功能?

(1) DEFLATE、Gzip、bzip2(支持切片)、LZO(支持切片)、Snappy
(2) 可以在mapreduce执行任务前(数据输入前的数据压缩)、任务中(map到reduce的数据传输过程中的数据压缩)、任务后(执行完毕后的数据压缩)
(3)压缩会占用一定的CPU资源,合理采用压缩可以减少磁盘io和网络数据传输,提高mr的整体运行效率原则:运算密集型任务少用压缩,IO密集型任务多使用压缩
(4)mr默认没有开启压缩功能
// 开启map端输出压缩
configuration.setBoolean(“mapreduce.map.output.compress”, true);
// 设置map端输出压缩方式
configuration.setClass(“mapreduce.map.output.compress.codec”, BZip2Codec.class, CompressionCodec.class);

//设置reduce端输出压缩开启
FileOutputFormat.setCompressOutput(job, true);
// 设置压缩的方式
FileOutputFormat.setOutputCompressorClass(job, BZip2Codec.class);

23.压缩概述:
鉴于磁盘I/O和网络带宽是hadoop的宝贵资源,数据压缩对于节省资源,最小化磁盘I/O和网络传输非常有帮助.可以在任意MapReduce阶段启用压缩
压缩策略和原则:
压缩是提高Hadoop运行效率的一种优化策略
通过对mapper,reducer运行过程的数据进行压缩,以减少磁盘IO,提高mp程序运行速度.
注意:采用压缩技术减少了磁盘IO,但同时增加了CPU运算负担.所以,压缩特性运用得当能提高性能,但运用不当也可能降低性能
压缩基本原则:
1):运算密集型的job,少用压缩
2):IO密集型的job,多用压缩
压缩方式:
DEFLATE:hadoop自带,直接使用,DEFLATE算法,文件扩展名为(.deflate),不可切分,和文本处理一样,不需要修改.
Gzip:hadoop自带,直接使用,DEFLATE算法,文件扩展名为(.gz),不可切分,和文本处理一样,不需要修改.
bzip2:hadoop自带,直接使用,bzip2算法,文件扩展名为(.bz2),可以切分,和文本处理一样,不需要修改.
LZO:hadoop没有,需要自己安装,LZO算法,文件扩展名为(.lzo),可以切分,需要建索引,还需要指定输入格式.
Snappy:hadoop没有,需要自己安装,Snappy算法,文件扩展名为(.snappy),可以切分,和文本处理一样,不需要修改.
压缩方式选择:
Gzip压缩:
优点:
压缩率比较高,而且压缩/解压速度也比较快,hadoop本身支持,在应用中处理Gzip格式的文件就和处理文本一样,大部分Linux系统都自带Gzip命令,使用方便.
缺点:
不支持Split
应用场景:
当每个文件压缩之后在130M以内的(一个块大小内),都可以考虑用Gzip压缩格式.
Bzip2压缩:
优点:
支持split;具有很高的压缩率,比Gzip压缩率都高,hadoop本身自带,使用方便.
缺点:
压缩/解压速度慢.
应用场景:
适合对速度要求不高,但需要较高的压缩率的时候;或者输出之后的数据比较大,处理之后的数据需要压缩存档减少磁盘空间并且以后数据用的比较少的情况;或者对单个很大的文本文件想压缩减少存储空间,同时又需要支持split,而且兼容之前的应用程序的情况.
LZO压缩:
优点:
压缩/解压速度也比较快,合理的压缩率;支持split,是hadoop中最流行的压缩格式;可以在linux系统下安装lzo命令,使用方便
缺点:
压缩率比Gzip要低一些,hadoop本身不支持,需要安装;在应用中对LZO格式的文本需要做一些特殊处理(为了支持split需要建索引,还需要指定inputFormat为lzo格式)
应用场景:
一个很大的文本文件,压缩之后还大于200M以上的可以考虑,而且单个文件越大,lzo优点越明显.
Snappy压缩:
优点:
高速压缩速度和合理地压缩率.
缺点:
不支持split,压缩率比Gzip要低,hadoop本身不支持,需要安装.
应用场景:
当mapreduce作业的map输出的数据比较大的时候,作为map到reduce的中间数据的压缩格式,或者作为一个mapreduce作业的输出和另外一个mapreduce作业的输入

24.压缩位置选择:
1):输入端采用压缩:
在有大量数据并计划重复处理的情况下,应该考虑对输入进行压缩,hadoop自动检查文件扩展名,如果扩展名能匹配,
就会用恰当的编解码方式对文件进行压缩和解压
2):mapper输出采用压缩:
当map任务输出的中间数据量很大是,应考虑在此阶段采用压缩技术.这能显著改善内部数据shuffle过程,而shuffle过程在
hadoop处理过程中资源消耗最多的环节,如果发现数据量造成网络传输缓慢,应该考虑使用压缩技术,可用于压缩mapper输出的
快速编解码器包括lzo或者snappy.
3):reducer输出采用压缩:
在此阶段启用压缩技术能够减少要存储的数据量,因此降低所需的磁盘空间.当mapreduce作业形成
作业链条时,因为第二个作业的输入也已压缩,所以启用压缩同样有效

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值