MapReduce框架

.MapReduce 的思想核心是 而治之 , 充分利用了并行处理的优势。
  1. Mapper map()方法是对输入的一个KV对调用一次!!
  2. Reduce Reduce()方法是对相同K的一组KV对调用执行一次
  3. Drive
二. MapReduce 原理分析
  1.  MapTask运行机制详解:

1. 首先,读取数据组件 InputFormat (默认 TextInputFormat )会通过 getSplits 方法对输入目录中文件进行逻辑切片规划得到splits ,有多少个 split 就对应启动多少个 MapTask split block 的对应关系默认是一对一。
2. 将输入文件切分为 splits 之后,由 RecordReader 对象(默认 LineRecordReader )进行读取,以 \n 作为分隔符,读取一行数据,返回<key value> Key 表示每行首字符偏移值, value 表示这一行 文本内容。
3. 读取 split 返回 <key,value> ,进入用户自己继承的 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 值都会被序列化成字节数组。
    环形缓冲区其实是一个数组,数组中存放着 key value 的序列化数据和 key value 的元数据信息,包括partition key 的起始位置、 value 的起始位置以及 value 的长度。环形结构是一个抽象概念。
     缓冲区是有大小限制,默认是100MB 。当 map task 的输出结果很多时,就可能会撑爆内存,所以需要在一定条件下将缓冲区中的数据临时写入磁盘,然后重新利用这块缓冲区。这个从内存往磁盘写数据的过程被称为Spill ,中文可译为溢写。这个溢写是由单独线程来完成,不影响往缓冲区写map结果的线程。溢写线程启动时不应该阻止 map 的结果输出,所以整个缓冲区有个溢写的比例spill.percent。这个比例默认是 0.8 ,也就是当缓冲区的数据已经达到阈值( buffer size * spillpercent = 100MB * 0.8 = 80MB),溢写线程启动,锁定这 80MB 的内存,执行溢写过程。 Maptask的输出结果还可以往剩下的 20MB 内存中写,互不影响。
6 、当溢写线程启动后,需要对这 80MB 空间内的 key 做排序 (Sort) 。排序是 MapReduce 模型默认的行为 !
     如果 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 对应数据的偏移量。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------

maptask的并行度(数量)

注意:默认spitsize == blocksize ==128m  这样的好处是为了所谓的数据本地化或hdfs的短路读取,减少一些没必要的网络资源。

MapTask 并行度是不是越多越好呢?(源码中的split_slop=1.1)
答案不是,如果一个文件仅仅比 128M 大一点点也被当成一个 split 来对待,而不是多个 split. MR 框架在并行运算的同时也会消耗更多资源,并行度越高资源消耗也越高,假设 129M 文件分为两个分片,一个是128M ,一个是 1M ;对于1M 的切片的 Maptask 来说,太浪费资源。
 

   2.ReduceTask 工作机制:

Reduce 大致分为 copy sort reduce 三个阶段,重点在前两个阶段。 copy 阶段包含一个eventFetcher来获取已完成的 map 列表,由 Fetcher 线程去 copy 数据,在此过程中会启动两个 merge 线程,分别为inMemoryMerger onDiskMerger ,分别将内存中数据 merge 到磁盘和将磁盘中的数据 进行merge 。待数据 copy 完成之后, copy 阶段就完成了,开始进行 sort 阶段, sort 阶段主要是执行 finalMerge操作,纯粹的 sort 阶段,完成之后就是 reduce 阶段,调用用户定义的 reduce 函数进行处理。
详细步骤
  1. Copy阶段,简单地拉取数据。Reduce进程启动一些数据copy线程(Fetcher),通过HTTP方式请求 maptask获取属于自己的文件。
  2. Merge阶段。这里的mergemap端的merge动作,只是数组中存放的是不同mapcopy来的数 值。Copy过来的数据会先放入内存缓冲区中,这里的缓冲区大小要比map端的更为灵活。merge 有三种形式:内存到内存;内存到磁盘;磁盘到磁盘。默认情况下第一种形式不启用。当内存中的 数据量到达一定阈值,就启动内存到磁盘的merge。与map 端类似,这也是溢写的过程,这个过 程中如果你设置有Combiner,也是会启用的,然后在磁盘中生成了众多的溢写文件。第二种 merge方式一直在运行,直到没有map端的数据时才结束,然后启动第三种磁盘到磁盘的merge 方式生成最终的文件。
  3. 合并排序。把分散的数据合并成一个大的数据后,还会再对合并后的数据排序。对排序后的键值对调用reduce方法,键相等的键值对调用一次reduce方法,每次调用会产生零个或者多个键值对,最后把这些输出的键值对写入到HDFS文件中。

ReduceTask并行度

MapTask 的并发数由切片数决定,ReduceTask 数量的决定是可以直接手动设置:
注意事项
1. ReduceTask=0 ,表示没有 Reduce 阶段,输出文件数和 MapTask 数量保持一致;
2. ReduceTask 数量不设置默认就是一个,输出文件数量为 1 个;
3. 如果数据分布不均匀,可能在 Reduce 阶段产生倾斜;
 
三.shuffle机制
 
map输入到reduce这个阶段的过程称为shuffle;

job对象进入后会有分区:

自定义分区小结:

分区是在map方法输出后在缓冲区内做的,他的参数就是map的输出的参数

1. 自定义分区器时最好保证分区数量与 reduceTask 数量保持一致;
2. 如果分区数量不止 1 个,但是 reduceTask 数量 1 个,此时只会输出一个文件。
3. 如果 reduceTask 数量大于分区数量,但是输出多个空文件
4. 如果 reduceTask 数量小于分区数量,有可能会报错
combiner合并小结
1. Combiner MR 程序中 Mapper Reducer 之外的一种组件
2. Combiner 组件的父类就是 Reducer
3. Combiner reducer 的区别在于运行的位置
4. Combiner 是在每一个 maptask 所在的节点运行 ;
5. Combiner 的意义就是对每一个 maptask 的输出进行局部汇总,以减小 网络传输量
6. Combiner 能够应用的前提是不能影响最终的业务逻辑,此外, Combiner 的输出 kv 应该跟 reducer 的输入kv 类型要对应起来。

排序

MapTask
      它会将处理的结果暂时放到环形缓冲区中,当环形缓冲区使用率达到一定阈值后,再对缓冲区中的数据进行一次快速排序,并将这些有序数据溢写到磁盘上,溢写完毕后,它会对磁盘上所有文件进行归并排序。
      ReduceTask 当所有数据拷贝完毕后, ReduceTask - 对内存和磁盘上的所有数据进行一次归并排序。
1. 部分排序 .
MapReduce 根据输入记录的键对数据集排序。保证输出的每个 文件内部有序
2. 全排序
最终输出结果只有 一个文件 ,且文件内部有序。实现方式是只设置 - - ReduceTask 。但该方法在处理大型文件时效率极低,因为- - 台机器处理所有文件,完全丧失了 MapReduce 所提供的并行架构。
3. 辅助排序 : ( GroupingComparator 分组 )
Reduce 端对 key 进行分组。应用于 : 在接收的 key bean 对象时,想让一个或几个字段相同 ( 全部字段比较不相同) key 进入到同一个 reduce 方法时,可以采用分组排序。
4. 二次排序 .
在自定义排序过程中,如果 compareTo 中的判断条件为两个即为二次排序。
 
GroupingComparator 是reduce端的组件:
      GroupingComparator mapreduce当中reduce端的一个功能组件,主要的作用是决定哪些数据作为一组,调用一次reduce的逻辑,默认是每个不同的key,作为多个不同的组,每个组调用一次reduce逻辑,我们可以自定义GroupingComparator实现不同的key作为同一个组,调用一次reduce逻辑。
 
MapReduce 读取和输出数据:
   InputFormat:InputFormat MapReduce 框架用来读取数据的类。
   分类:
  1. TextInputFormat (普通文本文件,MR框架默认的读取实现类型)
  2. KeyValueTextInputFormat(读取一行文本数据按照指定分隔符,把数据封装为kv类型)
  3. NLineInputF ormat(读取数据按照行数进行划分分片)
  4. CombineTextInputFormat(合并小文件,避免启动过多MapTask任务)
  5. 自定义InputFormat

CombineTextInputFormat:MR框架默认的TextInputFormat切片机制按文件划分切片,文件无论多小,都是单独一个切片, 然后由一个MapTask处理,如果有大量小文件,就对应的会生成并启动大量的 MapTask,而每个 MapTask处理的数据量很小大量时间浪费在初始化资源启动收回等阶段,这种方式导致资源利用 率不高。

CombineTextInputForma t 用于小文件过多的场景,它可以将 多个小文件从逻辑上划分成一个切 ,这样多个小文件就可以交给一个 MapTask 处理,提高资源利用率。
使用代码
            // 如果不设置 InputFormat ,它默认用的是 TextInputFormat.class
            job . setInputFormatClass ( CombineTextInputFormat . class );
            // 虚拟存储切片最大值设置 4m
            CombineTextInputFormat . setMaxInputSplitSize ( job , 4194304 );
 

CombineTextInputFormat的原理:切片生成过程分为两部分:虚拟存储过程和切片过程

假设设置 setMaxInputSplitSize 值为 4M
四个小文件: 1.txt -->2M ;2.txt-->7M;3.txt-->0.3M;4.txt--->8.2M
虚拟存储过程:把输入目录下所有文件大小,依次和设置的 setMaxInputSplitSize 值进行比较,如果不大于设置的最大值,逻辑上划分一个 。如果输入文件大于设置的最大值且大于两倍,那么以最大值切割一块;当剩余数据大小超过设置的最大值且不大于最大值2 倍,此将文件均分成2 个虚拟存储块(防止出现太小切片)。 比如如setMaxInputSplitSize 值为 4M ,输入文件大小为 8.02M ,则先逻辑上分出一个 4M 的块。剩余的大小为4.02M ,如果按照 4M 逻辑划分,就会出现 0.02M 的非常小的虚拟存储文件,所以将剩余的4.02M 文件切分成( 2.01M 2.01M )两个文件。
1.txt-->2M;2M<4M; 一个块;
2.txt-->7M;7M>4M, 但是不大于两倍,均匀分成两块;两块:每块 3.5M
3.txt-->0.3M;0.3<4M ,0.3M<4M , 一个块
4.txt-->8.2M; 大于最大值且大于两倍;一个 4M 的块,剩余 4.2M 分成两块,每块 2.1M
所有块信息:
2M 3.5M 3.5M 0.3M 4M 2.1M 2.1M 7 个虚拟存储块。
切片过程
判断虚拟存储的文件大小是否大于 setMaxInputSplitSize 值,大于等于则单独形成一个
切片。
如果不大于则跟下一个虚拟存储文件进行合并,共同形成一个切片。
按照之前输入文件:有 4 个小文件大小分别为 2M 7M 0.3M 以及 8.2M 这四个小文件,
则虚拟存储之后形成 7 个文件块,大小分别为:
2M 3.5M 3.5M 0.3M 4M 2.1M 2.1M
最终会形成 3 个切片,大小分别为:
2+3.5 M ,( 3.5+0.3+4 M ,( 2.1+2.1 M
注意:虚拟存储切片最大值设置最好根据实际的小文件大小情况来设置具体的值。
自定义inputformat:
    方案: 将多个小文件合并成一个 SequenceFile 文件( SequenceFile 文件是 Hadoop 用来存储二进制形式的 key-value 对的文件格式), SequenceFile 里面存储着多个文件,存储的形式为文件路径 + 名称为key,文件内容为 value
 
 
outputformat:
OutputFormat: MapReduce 输出数据的基类,所有 MapReduce 的数据输出都实现了 OutputFormat抽象类。下面我们介绍几种常见的OutputFormat 子类
TextOutputFormat
     默认的输出格式是 TextOutputFormat ,它把每条记录写为文本行。它的键和值可以是任意类型,因为TextOutputFormat 调用 toString() 方 法把它们转换为字符串。
SequenceFileOutputFormat
      将 SequenceFileOutputFormat 输出作为后续 MapReduce 任务的输入,这是一种好的输出格式,因为它的格式紧凑,很容易被压缩。

四 数据压缩机制:

需要压缩的地方:

Map输入端压缩  Map输出端压缩   Reduce端输出压缩
 
压缩配置:
设置 map 阶段压缩
Configuration configuration = new Configuration();
configuration.set("mapreduce.map.output.compress","true");
configuration.set("mapreduce.map.output.compress.codec","org.apache.hadoop.io.compress.SnappyCodec");
设置 reduce 阶段的压缩
configuration.set("mapreduce.output.fileoutputformat.compress","true");
configuration.set("mapreduce.output.fileoutputformat.compress.type","RECORD" );
configuration.set("mapreduce.output.fileoutputformat.compress.codec","org.ap ache.hadoop.io.compress.SnappyCodec");
 
配置文件压缩:
<property>
<name>mapreduce.output.fileoutputformat.compress</name>
<value>true</value>
</property>
<property>
<name>mapreduce.output.fileoutputformat.compress.type</name>
<value>RECORD</value>
</property>
<property>
<name>mapreduce.output.fileoutputformat.compress.codec</name>
<value>org.apache.hadoop.io.compress.SnappyCodec</value>
</property>
 

 

   
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值