hadoop-MapReduce总结

1.定义

是一个分布式运算程序的编程框架,能将用户编写的业务逻辑代码自带默认组件整合成一个完成的分布式运算程序。

2.优缺点

2.1优点

2.1.1易于编程

只需要简单的实现一些接口,就可以完成一个分布式程序。

2.1.2高容错性

mr程序可以部署在多台机器上,其中一台挂了,可以把上面的计算任务转移到另外一个节点上运行,由hadoop内部自动完成。

2.1.3良好的扩展性

可以通过增加机器来有效扩展其计算能力。

2.1.4海量数据的离线处理

实现千台服务器集群并发工作,提供数据处理能力。

2.2缺点

2.2.1实时计算(x)

无法处理毫秒、秒级响应。

2.2.2流式计算(x)

MR的输入数据集是静态的无法适应流式计算动态输入数据。

2.2.3有向无环图计算(x)

由于mr作业的输出结果都会写入到磁盘中,当存在多个依赖的应用程序时,前一个应用的输出作为后一个应用的输入,这样就会导致大量的磁盘IO,影响性能。

3.初步了解MR

3.1实例进程

一个完整的MR程序在分布式运行时有三类实例进程

3.1.1MrAppMaster

负责整个程序的过程调度及状态协调。

3.1.2MapTask

负责Map阶段的整个数据处理流程

3.1.3ReduceTask

负责Reduce阶段的整个数据处理流程

3.2编写规范

我们通常在编写MR的java程序的时候,一般有三部分即XxMapper、XxReducer、XxDriver。后面以wordCount案例为例子说明

3.2.1Mapper

public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {

    private final Text outK = new Text();
    private final IntWritable outV = new IntWritable(1);

    @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) {
            outK.set(word);
            context.write(outK, outV);
        }
    }
}

①我们创建的类WordCountMapper需要继承父类Mapper。

②其中还需要指定Mapper的输入输出的kv类型。

③其中Mapper的输入涉及到InputFormat,其默认是TextFormat,表示输入的k是偏移量,v是一行数据,所以大多数情况下输入的KV基本是LongWritable和Text。 

④至于Mapper输出的KV是根据自己的业务来定,比如WordCount案例Mapper阶段将单词变为(word,1)的格式。所以k是Text,v是IntWritable。

⑤重写map方法,这里就是我们重点编程的地方,主要是写业务逻辑,可以简单的理解为输入数据中的每一行都会执行这个map方法,也就是说有多少行,map就执行多少次,所以编程的时候我们就可以把重心放在处理每行上。

扩展:其实Mapper阶段还可以重写setup和cleanup方法 ,其中setup主要做一些初始化或者预先操作,比如可以在setup阶段读取缓存中数据用于map方法处理业务逻辑;cleanup主要用于最后收尾,比如如果之前打开了流,可以在这里关闭。

3.2.2Reducer

public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {

    private final IntWritable outV = new IntWritable();;

    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        int sum = 0;

        for (IntWritable value : values) {
            sum += value.get();
        }

        outV.set(sum);

        context.write(key, outV);
    }
}

①我们创建的类WordCountReducer需要继承父类Reducer。

②同样的需要指定Reducer的输入输出类型。

③至于其输入类型,一般情况和Mapper的输出类型相同。

④输出类型由我们业务来定,由于最后输出的是(word,count),所以k是Text,v是IntWritable。

⑤重写reduce方法,在reduce中写业务逻辑,首先我们要有一个简单认知,在reduce阶段的时候,mapper阶段得到的结果相同的key会被分到一组,这一组中的value则聚合成一个集合,和spark中的groupByKey很像。简单来说就是加入mapper得到结果(emt,1),(emt,1),(emt,1)就会在执行reduce被分组为(emt,col(1,1,1));也就是reduce执行的次数就是mapper得到的结果中key的种类数。我们此时只需要在reduce中对col(1,1,1)进行简单的相加操作,就能得到(emt,3)了。

3.2.3Driver

这个比较八股文,理解加背诵即可。

public class WordCountDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        //1.获取job
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);

        //2.设置jar路径
        job.setJarByClass(WordCountDriver.class);

        //3.关联mapper和reducer
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);

        //4.设置map输出的kv类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        //5.设置最终输出的kv类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //可选。手动设置reduce任务个数
        job.setNumReduceTasks(2);

        //6.设置输入输出路径
        FileInputFormat.setInputPaths(job, new Path("datas\\mr\\hello.txt"));
        FileOutputFormat.setOutputPath(job, new Path("datas\\mr\\output1"));
        //7.提交job
        boolean result = job.waitForCompletion(true);
        System.exit(result ? 0 : 1);
    }
}

由于我这些程序就只是简单的用着本地hadoop跑的。

如果是yarn集群话,相当于YARN集群的客户端,用于提交我们整个程序到YARN集群,提交的是
封装了MapReduce程序相关运行参数的job对象

3.3(反)序列化

其实对java有一定基础的小伙伴对于序列化一定不会陌生了。

3.3.1什么是(反)序列化

序列化是把内存中的对象转换为字节序列以便于持久化网络传输

反序列化是将字节序列或者硬盘的持久化数据转换成内存中的对象。

3.3.2为什么要序列化

存在内存中的对象断电就消失且只能在本地进程使用,不能被发送到网络上;也就是说序列化帮助存储与网络传输

3.3.3Hadoop序列化vsJava序列化

因为java的序列化不够轻量,被序列化后的对象会附带较多的额外信息,比如校验信息,头header等等,传输不够高效,于是hadoop自己使用一套更轻量的序列化机制。从Serializable变为Writable。与java类型的对应关系如下,基本就是后面多了个Writable后缀,其中需要特别注意的是String并不是简单加后缀,而是变成了Text

Java类型

Hadoop Writable类型

Boolean

BooleanWritable

Byte

ByteWritable

Int

IntWritable

Float

FloatWritable

Long

LongWritable

Double

DoubleWritable

String

Text

Map

MapWritable

Array

ArrayWritable

Null

NullWritable

3.3.4自定义对象的序列化?

需要以下几个步骤:

①实现Wirtable接口

②重写序列化方法和反序列化方法,且顺序完全一致

③根据业务最后输出格式的需要,适当重写toString方法

 ④如何后面处理的过程中该对象被作为了k使用,则必须实现comparable接口并重写compareTo方法,因为mr框架的shuffle过程会对key进行排序。

4深入理解MR

4.1MR基本组成框架

4.2Job提交

详情见这篇文章:Job提交流程

4.3InputFormat

从源码中我们可以发现InputFormat是抽象类

我们发现有好多类继承了它并实现了抽象方法getSplits

4.3.1TextInputFormat

而其中FileInputFormat也有许多类继承其,而默认的最常见的就是TextInputFormat,按行读取每条记录。是存储该行在整个文件中的起始字节偏移量LongWritable类型。这行的内容,不包括任何行终止符(换行符和回车符),Text类型。

4.3.2CombineTextInputFormat

 由于之前我们分析源码的时候说过FileInputFormat每个文件单独切片的,也就是说一个小文件它一定会单独切成一片,由于每个切片都会开启一个MapTask,你开启一个MapTask少说也得一个CPU,1G内存,如果该文件就1kb,有必要吗?所以说在有多个小文件时,这样做会产生大量的MapTask,效率低。

而CombineTextInputFormat就适用于小文件过多的情景,将多个小文件逻辑上规划到一个切片中,让其只交给一个MapTask处理。

其切片机制包含两部分:虚拟存储过程和切片过程二部分。

4.4MapTask

详情见这篇文章:MapTask

4.5shuffle机制

Map方法之后,Reduce方法之前的数据处理过程称之为shuffle。

 4.5.1可选流程combine

Combiner的意义就是对每一个MapTask的输出进行局部汇总,以减小网络传输量,使得传到reduce的数据量小了,比如wordcount中的(emt,1),(emt,1)直接先处理为(emt,2)。有点像之前spark探讨的reduceByKey和groupByKey,详情见这篇文章:spark常用转换算子

不过combiner的使用的前提是不影响最终业务结果,比如求平均数就不宜使用。

自定义Combiner实现步骤:

①自定义一个Combiner继承Reducer,重写Reduce方法;

②在驱动类中设置

job.setCombinerClass(WordCountCombiner.class);

其实一般情况,可以直接把自定义reducer的逻辑拿来用即可,也就是说。

job.setCombinerClass(WordCountReducer.class);

4.5.2分区

默认分区是根据key的hashCode对ReduceTask个数取模得到的。

分区与ReduceTask之间的关系总结

①如果ReduceTask>分区结果数,则会产生几个空的输出文件part-r-xxxxx文件;

②如果ReduceTask属于区间(1,分区结果数),则有一部分数据无处安放,会报异常;

③如果ReduceTask=1,不论分区结果数多少,最终只会产生一个结果文件part-r-00000;

④分区号必须从零开始,逐一累加,因为如果不是逐一累加,中间就有空白文件,浪费资源;

4.6ReduceTask

详情见这篇文章:ReduceTask

4.7OutputFormat

OutputFormat是一个抽象类

 有许多类继承了其,我们默认是TextOutputFormat,它又继承自FileOuputFormat。

我们发现FileOuputFormat中有一个抽象方法getRecordWriter,这个是核心 

TextOutputFormat通过该方法getRecordWriter来实现一行一行的输出到文件中

 4.7.1自定义OutputFormat步骤

由于一些场景需要输出数据到特地名字文件或者数据库、搜索引擎等等,所以需要自定义OutputFormat

①自定义一个类XxOutputFormat继承FileOutputFormat,重写getRecordWriter方法;

②由于getRecordWriter需要返回RecordWriter类型的对象,又需要自定义一个类XxRecordWrite继承RecordWrite,重写LogRecordWrite(主要用户初始化连接或者流创建)、write(主要业务逻辑)、close(关闭连接或者流)。

③在自定义的XxOutputFormat的getRecordWriter方法中直接new一个XxRecordWrite对象返回即可。

④最后在driver模块中记得设置一下:

//设置自定义的outputformat
job.setOutputFormatClass(XxOutputFormat.class);

4.8排序

排序操作是Hadoop的默认行为,MapTask和ReduceTask均会对数据按照key进行排序。任何应用程序中的数据均会被排序,而不管逻辑上是否需要。默认排序是按照字典顺序排序,且实现该排序的方法是快速排序

MapTask和ReduceTask中都涉及到排序,当MapTask中的环形缓冲区使用率达到一定阈值或者数据读完后,会对缓冲区中的数据进行一次快速排序并溢写到磁盘上,而当数据处理完毕后,也还对磁盘上的文件进行归并排序。对于ReduceTask则会统一对内存和磁盘上的所有数据进行一次归并排序

4.8.1部分排序

MapReduce根据输入记录的键对数据集排序。保证输出的每个文件内部有序

4.8.2全排序

最终输出结果只有一个文件,且文件内部有序。实现方式是只设置一个ReduceTask。 但是这种方法慎用,尤其是生产环境下,数据量非常大,一台机器一个ReduceTask处理,完全违背了MR提供的并行计算架构思想,效率极低。

4.8.3辅助排序(GroupingComparator分组)

在Reduce端对key进行分组。应用于:在接收的key为自定义对象时,让对象中一个或几个字段相同(不包含全部字段相同)的key进入到同一个reduce方法时 ,可以采用分组排序

4.8.4二次排序

在自定义排序过程中,如果compareTo中的判断条件为两个即为二次排序。比如一个自定义对象中含有时间和价格字段,这两都是排序条件,例如先按价格倒序,如果价格相同,在按时间倒序等等

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mapreduce实验报告 前言和简介 MapReduce是Google提出的一种编程模型,在这个模型的支持下可以实现大规模并行化计 算。在Mapreduce框架下一个计算机群通过统一的任务调度将一个巨型任务分成许多部分 ,分别解决然后合并得到最终结果。Mapreduce可以让程序员以简单的程序来解决实际问 题,而隐藏了诸如分布、工作调度、容错、机器间通信,使得大规模任务简单而迅速地 完成。 1. Mapreduce的基本原理 1. 核心思想。 "Divide and Conquer"是Mapreduce的核心思想。面对一个规模庞大的问题,要 处理是以TB计的数据,Mapreduce采用"输入"------"分解"------"解决"----- -"聚合"------"输出结果"的基本过程。 2. 基本原理 Map和Reduce是两个核心操作,用户定义的map函数接收被切割过的原始的key/ value对集并且计算出一个中间key/value对集。Mapreduce库函数将所有的具有 相同key值的value聚合在一起交给用户定义的reduce函数处理。reduce函数将 同一key值的所有value合并成得到输出文件。在整个过程中,Mapreduce库函数 负责原始数据的切割,中间key/value对集的聚合,以及任务的调度,容错、通 信控制等基础工作。而用户定义的map和reduce函数则根据实际问题确定具体操 作。 2. 框架的基本结构和执行流程 基本结构 Mapreduce框架的主要程序分为三种即Master,Map和Reduce。 1. Master:主要功能有两个,任务的分割和任务的调度。Master把输入文件切成许 多个split,每个split文件一般为几十M。Master同时还要调度任务监视各个 map worker和reduce worker的工作状态,以做出相应的安排。Master还要监视各个子任务的完成进 展情况。 Master用到的数据结构 Struct Split[] //文件切割后的信息 struct MapSTATE[] //记录各个map任务的情况。 struct ReduceSTATE[R] //各个reduce任务的情况。 Type Map=0,Reduce=0 //记录map任务和reduce任务的完成个数。 MapWorkerSTATE[] ReduceWorkerSTATE[] //各个工作机器的忙闲状态 FileSplit(string inputfilename) //输入文件切割 JobAssign() //工作任务分配 2. Map:主要功能是读取经过切割split文件形成一个map任务,分析map任务,得到 中间结构并且将同一类型的中间文件存放在同一个区域内等待特定的reduce程 序读取。 3. Reduce:不同的Reduce读取各个Map得到的特定的中间文件,将所有相同的中间 文件整合成最后的输出文件。 任务执行基本流程 基本流程图见下一页 首先输入收据文件被Mapreduce库函数分割成M个split集。用户定义的程序被 拷贝到机群中,其中一个是master,其它的都是worker。M个map任务和R个reduc e任务将被分配。Master负责调度任务和过程监视。随时检测worker的工作状况, 任务的完成进度。Map worker每完成一个子任务向master报告。 一个被分配了map任务的worker读取一个split集,该worker从这个split集中 分析出key/value对,然后有map函数来处理这些key/value对并得到中间key/val ue对,这些key/value对将最终存放在map worker的本地硬盘上。每完成一个任务报告master。 中间key/value对被存在本地硬盘的R个不同的区域中,由于可能的key值很可 能不止R个,故必须利用一个分割函数来划分中间文件,常用的是散列的方法(如 hash(key) mod R)。保证key值相同的key/value对被存放同一区域中,并且将位置报告给maste r。如果同一个key的中间文件多而小可以考虑用cmobine函数在本地进行合并。 当所有的split都被分析完成之后,reduce worker开始工作,每个reduce根据master的安排和信息指示利用机群的内部文件 系统读取map worker本地磁盘中特定位置的中间文件。 Reduce开始聚合中间文件,得到自己的输出文件。在聚合的过程中由于有很 多key值,一般将用到排序。Reduce worker完成自己的工作后向master报告。 控制 分析key/value对 分区写入磁盘 读取 *单向箭头表示控制,双向箭头表示控制

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值