MapReduce入门学习

一.MAPREDUCE框架结构及核心运行机制

Mapreduce是一个分布式运算程序的编程框架,是用户开发“基于hadoop的数据分析应用”的核心框架;Mapreduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个hadoop集群上。

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

1、MRAppMaster:负责整个程序的过程调度及状态协调

2、mapTask:负责map阶段的整个数据处理流程

3、ReduceTask:负责reduce阶段的整个数据处理流程

MapReduce程序实现的设计思想:

设计思想

整个mapreduce程序框架执行都是基于上述三个组件,大致思路如下:

1.mapreduce客户端,产生计算任务,实例化job对象,将实例化后的job对象输出为一个配置文件、jar包(包括指定输入文件路径、输出文件路径、jar包路径、map和reduce方法执行所在class及其输入输出类型等),执行submit方法,将信息提交给yarn。

2.yarn获得了客户端发来的信息后,会启动一个mr appmaster程序,用来统筹mapTask和reduceTask:

A.一个mr程序启动的时候,最先启动的是MRAppMaster,MRAppMaster启动后根据本次job的描述信息,计算出需要的maptask实例数量,然后向集群申请机器启动相应数量的maptask进程。maptask进程启动之后,根据给定的数据切片范围进行数据处理,主体流程为:

a)利用客户指定的inputformat来获取RecordReader读取数据,形成输入KV对

b)将输入KV对传递给客户定义的map()方法,做逻辑运算,并将map()方法输出的KV对收集到缓存

c)将缓存中的KV对按照K分区排序后不断溢写到磁盘文件

注:mapTask一次读取文件的一行数据,调用map方法执行逻辑

B.MRAppMaster监控到所有maptask进程任务完成之后,会根据客户指定的参数启动相应数量的reducetask进程,并告知reducetask进程要处理的数据范围(数据分区)

C.Reducetask进程启动之后,根据MRAppMaster告知的待处理数据所在位置,从若干台maptask运行所在机器上获取到若干个maptask输出结果文件,并在本地进行重新归并排序,然后按照相同key的KV为一个组,调用客户定义的reduce()方法进行逻辑运算,并收集运算输出的结果KV,然后调用客户指定的outputformat将结果数据输出到外部存储

注:reduceTask每次读取相同的key作为一次reduce方法执行的入参,执行这一组数据

二.解析MapTask和ReduceTask并行度决定机制

1. mapTask并行度的决定机制

maptask的并行度决定map阶段的任务处理并发度,进而影响到整个job的处理速度

那么,mapTask并行实例是否越多越好呢?其并行度又是如何决定呢?

一个job的map阶段并行度由客户端在提交job时决定,而客户端对map阶段并行度的规划的基本逻辑为:

将待处理数据执行逻辑切片(即按照一个特定切片大小,将待处理数据划分成逻辑上的多个split),然后每一个split分配一个mapTask并行实例处理

这段逻辑及形成的切片规划描述文件,由FileInputFormat实现类的getSplits()方法完成,其过程如下图:

根据源码进行分析

FileInputFormat切片机制

1、切片定义在InputFormat类中的getSplit()方法

代码分析

2、FileInputFormat中默认的切片机制:

简单地按照文件的内容长度进行切片;切片大小,默认等于block大小;切片时不考虑数据集整体,而是逐个针对每一个文件单独切片

比如待处理数据有两个文件:file1.txt    320M;file2.txt    10M

经过FileInputFormat的切片机制运算后,形成的切片信息如下: 

file1.txt.split1--  0~128

file1.txt.split2--  128~256

file1.txt.split3--  256~320

file2.txt.split1--  0~10M

3、FileInputFormat中切片的大小的参数配置

通过分析源码,在FileInputFormat中,计算切片大小的逻辑:Math.max(minSize, Math.min(maxSize, blockSize));  切片主要由这几个值来运算决定

minsize:默认值:1  配置参数: mapreduce.input.fileinputformat.split.minsize   

maxsize:默认值:Long.MAXValue  配置参数:mapreduce.input.fileinputformat.split.maxsize

因此,默认情况下,切片大小=blocksize

maxsize(切片最大值):参数如果调得比blocksize小,则会让切片变小,而且就等于配置的这个参数的值

minsize (切片最小值):参数调的比blockSize大,则可以让切片变得比blocksize还大

2. ReduceTask并行度的决定

reducetask的并行度同样影响整个job的执行并发度和执行效率,但与maptask的并发数由切片数决定不同,Reducetask数量的决定是可以直接手动设置:

//默认值是1,手动设置为4

job.setNumReduceTasks(4);

如果数据分布不均匀,就有可能在reduce阶段产生数据倾斜

注意:reducetask数量并不是任意设置,还要考虑业务逻辑需求,有些情况下,需要计算全局汇总结果,就只能有1个reducetask

尽量不要运行太多的reduce task。对大多数job来说,最好reduce的个数最多和集群中的reduce持平,或者比集群的 reduce slots小。这个对于小集群而言,尤其重要

什么是集群中的reduce? reduce slots?

job执行完submit函数,结果是,形成一个job.xml(配置信息),一个mapreduce程序jar包,一个job.split(分片信息),yarn将这些文件发送给mr app master,此时mr就有了可以统筹maptask和reducetask运行的所有信息了。

以上信息都是mapreduce客户端与namenode交互,利用hdfsAPI获取文件信息,然后将信息进行处理,之后的内容才是mapreduce程序如何执行。

三.mapreduce的shuffle机制

原理图

mapreduce中,map阶段处理的数据如何传递给reduce阶段,是mapreduce框架中最关键的一个流程,这个流程就叫shuffle;

shuffle: 洗牌、发牌——(核心机制:数据分区,排序,缓存,combiner);

具体来说:就是将maptask输出的处理结果数据,分发给reducetask,并在分发的过程中,对数据按key进行了分区和排序;

详细步骤:

map阶段

1.首先,读取数据组件InputFormat(默认TextInputFormat)会通过getSplits方法对输入目录中文件进行逻辑切片规划得到splits,有多少个split就对应启动多少个MapTask。split与block的对应关系默认是一对一。

2.将输入文件切分为splits之后,由RecordReader对象(默认LineRecordReader)进行读取,以\n作为分隔符,读取一行数据,返回。Key表示每行首字符偏移值,value表示这一行文本内容。

3.读取split返回,进入用户自己继承的Mapper类中,执行用户重写的map函数。RecordReader读取一行这里调用一次。

4.map逻辑完之后,将map的每条结果通过context.write进行collect数据收集。在collect中,会先对其进行分区处理,默认使用HashPartitioner(可自定义分区方式)。

MapReduce提供Partitioner接口,它的作用就是根据key或value及reduce的数量来决定当前的这对输出数据最终应该交由哪个reduce task处理。默认对key hash后再以reduce task数量取模。默认的取模方式只是为了平均reduce的处理能力,如果用户自己对Partitioner有需求,可以订制并设置到job上。

5.接下来,会将数据写入内存,内存中这片区域叫做环形缓冲区,缓冲区的作用是批量收集map结果,减少磁盘IO的影响。我们的key/value对以及Partition的结果都会被写入缓冲区。当然写入之前,key与value值都会被序列化成字节数组。

      5.1 环形缓冲区其实是一个数组,数组中存放着key、value的序列化数据和key、value的元数据信息,包括partition、key的起始位置、value的起始位置以及value的长度。环形结构是一个抽象概念。 ————>所以在数据进入缓冲区后,便会调用partition方法对数据进行分区了,分区数据、偏移量等信息都存在相应数据结构中。

https://blog.csdn.net/lfdanding/article/details/51412591      源码分析,缓冲区的数据结构以及溢写流程

      5.2 缓冲区是有大小限制,默认是100MB。当map task的输出结果很多时,就可能会撑爆内存,所以需要在一定条件下将缓冲区中的数据临时写入磁盘,然后重新利用这块缓冲区。这个从内存往磁盘写数据的过程被称为Spill(溢写)。由单独线程完成,不影响往缓冲区写map结果的线程。溢写线程启动时不应该阻止map的结果输出,所以整个缓冲区有个溢写的比例spill.percent。这个比例默认是0.8,也就是当缓冲区的数据已经达到阈值(buffer size * spill percent = 100MB * 0.8 = 80MB),溢写线程启动,锁定这80MB的内存,执行溢写过程。Map task的输出结果还可以往剩下的20MB内存中写,互不影响。

6.当溢写线程启动后,需要对这80MB空间内的key做排序(Sort)。排序是MapReduce模型默认的行为,这里的排序也是对序列化的字节做的排序。可能有多个溢出文件,每个溢写文件都是经过分区和排序处理后的数据生成的。

      6.1 溢写步骤

      利用快速排序算法对缓存区内的数据进行排序,排序方式是,先按照分区编号partition 进行排序,然后按照key 进行排序。这样,经过排序后,数据以分区为单位聚集在一起,且同一分区内所有数据按照key 有序。

      按照分区编号由小到大依次将每个分区中的数据写入任务工作目录下的临时文件output/spillN.out(N 表示当前溢写次数)中。如果用户设置了Combiner,则写入文件之前,对每个分区中的数据进行一次聚集操作。

      如果有多个溢写的文件,将各个溢写文件按照归并排序的方式合并成一个文件

      6.2 如果job设置了Combiner,那就是使用Combiner的时候。将有相同key的key/value对的value加起来,减少溢写到磁盘的数据量。Combiner会优化MapReduce的中间结果,所以它在整个模型中会多次使用。

      那哪些场景才能使用Combiner呢?从这里分析,Combiner的输出是Reducer的输入,Combiner绝不能改变最终的计算结果。Combiner只应该用于那种Reduce的输入key/value与输出key/value类型完全一致,且不影响最终结果的场景。比如累加,最大值等。Combiner的使用一定得慎重,如果用好,它对job执行效率有帮助,反之会影响reduce的最终结果。

7.每次溢写会在磁盘上生成一个临时文件(须先判断是否有combiner),如果map的输出结果真的很大,有多次这样的溢写发生,磁盘上相应的就会有多个临时文件存在。当整个数据处理结束之后开始对磁盘中的临时文件进行merge合并,因为最终的文件只有一个(总的分好区且有序的数据文件),写入磁盘,并且为这个文件提供了一个索引文件,以记录每个reduce对应数据的偏移量。

8.map整个阶段结束。

溢写到临时文件,为什么会有多个临时文件?

一次溢写数据量为80M,如果一个block大于80M,maptask当然会分多次溢写,所以会形成多个溢写的临时文件

combiner的使用要注意不能破坏你的结果,思考maptask阶段会有哪些步骤用到combiner

每个maptask在溢写过程中就会调用combiner,如果溢写生成多个临时文件,最后要生成一个唯一结果文件,将临时文件合并,此时还要调用combiner

自定义辅助排序接口groupingComparator的使用。

reduce阶段

MapTask执行完之后,生成一个分区且排序的文件,mr appMaster会监控MapTask的执行,默认情况下,当Map任务完成个数达到Map任务总数的5%时,MRAppMaster开始向Yarn为Reduce申请Container,并启动Reduce进程。

此时Reduce启动后拉取每个Map的结果集中属于自己的那个分区的数据。注意这时候Reduce虽然启动了,但执行的操作只是拉取分区数据,也就是说必须所有的Map任务全部完成,所有的分区数据都已经拉取,Reduce阶段才真正开始处理数据。

Reduce阶段可以分为三个阶段:①Map结果数据拉取;②合并排序;③执行Reduce处理逻辑。

①Map结果数据拉取:通过HTTP请求从Shuffle HTTP Server拉取数据。

Shuffle HTTP Server是由NodeManager启动的。使用的是Yarn的AuxServices机制,NodeManager允许用户通过配置附属服务的方式扩展自己的功能,这使得每个节点可以定制一些特定框架需要的服务。附属服务需要在NodeManagger启动前配置好,并由NodeManagger统一启动和关闭。Map阶段将结果数据提交到Shuffle HTTP Server后Map进程就退出了,后续Reduce进程是从Shuffle HTTP Server拉取数据的。

②合并排序:获取到各个maptask结果文件的所属分区,将若干个分区合并成一个文件,然后使用归并排序的方法对数据按照key进行排序,排序规则默认按照hash的方式,也可通过自定义实现groupingComparator接口实现排序规则

③执行Reduce处理逻辑:每次处理一组相同key的数据,为形式,对数据进行处理,一次处理一组

你可能感兴趣的:(MapReduce入门学习)