MapReduce学习

--MapReduce概述
     MapReduce是一种分布式计算模型,由Google提出,主要用于搜索领域,解决海量数据的计算问题。
     MR由两个阶段组成:Map和Reduce,用户只需要实现map()和reduce()两个函数,即可实现分布式计算,非常简单。
-map阶段
     1.读取输入文件内容,解析成key,value对。对输入文件的每一行,解析成key,value对。每一个键值对调用一次map函数。
     2.写自己的逻辑,对输入的key,value处理,抓换成新的key,value输出
     3.对输出的key,value进行分区
     4.对不同分区的数据,按照key进行排序,分组。相同的key的value放到一个集合中
     5.(可选)分组后的数据进行归约
-reduce阶段
     1.对多个map任务的输出,按照不同的分区,通过网络copy到不同的reduce节点
     2.对多个map任务的输出进行合并,排序,写reduce函数自己的逻辑,对输入的key,value处理,转换成新的key,value输出
     3.把reduce的输出保存到文件中

-- MapReduce原理


maptask端执行过程:
     mapper端主要有五大步骤:读取(read),map,收集(collect),溢出(spill)和规约(combine):
     1.map task端通过inputformat和getsplits方法从HDFS读取一个block数据块进行切片处理,然后交给map方法处理。

     2.每个maptask都有一个循环利用的缓冲区(默认大小是100M,通过io.sort.mb设置),mapper把处理好的数据写到缓冲区,当缓冲区到达io.sort.spill.percetnt设置的阈值(默认是0.8)时,会触发一个后台线程将缓冲区中的数据spill(“溢出写”)到磁盘中,当缓冲区的数据到达100%的时候,由于mapper处理的数据没有地方放了,所以一会被阻塞直至缓冲区有空间地方才重新处理并写数据到缓冲区。
    
  3.在缓冲区的数据被spill(“溢出写”)到磁盘之前,先对缓冲区中的数据进行快速排序:按照分区编号partition进行排序,然后在按照key排序。这样排序完以后,这批数据就按照分区聚集在一起,且同一分区的数据是按照key有序的。然后把这几组数据(分区有几个,数据就分成几组)写到磁盘中。

     4.由于mapper在进行split的时候,可能产生很多小文件,这些小文件分别属于不同的分区,每个分区有若干小文件,这时就需要merge操作,把这些小文件合并起来,每个partition都对应一个段(segment)列表,段列表中记录着所有的split文件中对应的这个partition那段数据的文件名,起始位置,长度等。所以首先对partition对应的所有的segment进行合并,合并成一个大的segment。如果这个partition有很多segment,则需要分批对其进行合并,并把索引数据放到index文件中。

     5.如果程序设置了combine(job.setCombinerClass(MyReducer.class)),则在combine之前,程序会进行一次综合的聚合操作,将所有的partition都各自合并成一个文件以方便combine操作,combine具体操作跟reducer端的操作一样,唯一不同的是:reducer是对全局的某个partition进行操作,但是combine操作是对本节点上的所有partition各自进行操作。

--reducetask
redu端主要有三大步骤:复制(copy),排序(sort)和reducer操作:
     1.复制:reducer执行前,先把数据从各个mapper节点中fetch(启动一组fetcher线程组去抓数据)到本节点,如果数据大小超过了一定的阈值(mapreduce.reduce.shuffle.input.buffer.percent默认配置是0.9,也是属于溢出写),则把数据写到磁盘中(onDiskMapOutput实例),否则就存储在内存中(InMemoryMapOutput实例)。在远程copy数据到本地的同时,reducer会启动两个后台线程对已经抓过来的存储在内存和磁盘的数据进行合并,防止内存使用过多和磁盘文件过多。
     2.排序:sort操作相当于是map端sort的延续。排序操作会在所有的文件都复制到本地之后开启,使用Merger工具类进行排序(采用归并排序算法)所有的文件,经过排序过程后,会合并成一个大的文件。
     3.reducer操作,reducer实例对象读取上述得到的大文件,并进行reducer操作,处理完毕后,将结果写入HDFS中

--shuffle过程
     mapreduce,map阶段处理的数据如何传递给reduce阶段,是mapreduce框架中最关键的一个流程,这个流程就叫shuffle;
     shuffle:洗牌,发牌-(核心机制:数据分区,排序,缓存)
具体来说:就是将maptask输出的处理结果数据,分发给reducetask,并在分发的过程中,对数据按key进行了分区和排序;



1.maptask收集我们的map()方法输出的kv对,放到内存缓冲区中,
2.从内存缓冲区不断溢出本地磁盘文件,可能会溢出多个文件
3.多个溢出文件会被合并成大的溢出文件
4.在溢出的过程中,及合并的过程中,都要调用partitoner进行分组和针对key进行排序
5.reducetask根据自己的分区号,去各个maptask机器上取相应的结果分区数据
6.reducetask会取到同一分区的来自不同maptask的结果文件,reducetask会将这些文件在进行合并(归并排序)
7.合并成大文件后,shuffle的过程也就结束了,后面进去reducetask的逻辑运算guoch(从文件中取出一个一个的键值对group,调用用户自定义的reduce()方法)
备注:shuffle中的缓冲区大小影响到mapreduce程序的执行效率,原则上说,缓冲区越大,磁盘io的次数越少,执行速度就越快。缓冲区的代销可以通过参数调整,参数:io.sort.mb 默认100M

--序列化机制与Writable接口
-hadoop序列化机制
     所谓的序列化,就是将结构化对象转换为字节流,以便在网络上传输或是写到磁盘进行永久存储,反序列化,就是将字节流转化为结构化对象。序列化在分布式数据处理的两大领域经常出现:进程间通信和永久存储。
    在Hadoop中,系统中多个节点上进程间的通信是通过“远程过程调用”(remote procedure call,RPC)实现的。RPC将信息序列化成二进制流后发送到远程节点,远程节点接着将二进制流反序列化为原始信息,通常情况下,PRC序列化格式紧凑,快速,可扩展!紧凑的格式能够使我们充分利用数据中心最稀缺的资源--网络宽带。
 在Hadoop中,它使用自己的序列化框架Writable,序列化需要实现一个叫Writeable的接口,类似于jdk的serializable接口。
-Writable接口
     序列化抓住两个关键:序列化和反序列化。所有的都是围绕这两个展开的。
无非就是把机构化数据转化为字节流或者把字节流转化为结构化对象。
     Writable接口定义了两个接口,一个是将其状态写入到dataoutput二进制流,另一个是从datainput中读取结构化对象。

--Hadoop内置的数据类型


BooleanWritable:标准布尔型数值
ByteWritable:单字节数值
DoubleWritable:双字节数值
FlotWritable:浮点数
IntWritable:整型数
VIntWritable:可变整型数
LongWritable:长整型数
VLongWritable:可变长整型数
Text:使用UTF8格式存储的文本
NullWritable:当中的key或value为空时使用

-自定义数据类型
     1.继承接口Writable,实现其方法write()和readFields(),以便该数据能被序列化后完成网络传输或文件输入/输出;
     2.如果该数据需要作为主键key使用,或需要比较数值的大小时,则需要实现WritableComparable接口,实现其方法write(),readField(),CompareTo()

--MapTask并行度决定机制
-MapTask并行度决定机制
一个job的map阶段并行度由客户端在提交job时决定,而客户端对map阶段并行度的规划的基本逻辑为:
     将待处理数据执行逻辑切片(即按照一个特定切片大小,将待处理数据划分成逻辑上的多个split),然后每一个split分配一个maptask并行实例处理。
     这段逻辑及想成的切片规划描述文件 ,由inputformart实现类的getsplit()方法完成。
--FileInputFormat切片机制
     通过分析源码,在FileinoutFormat中,计算切片大小的逻辑:
Math.max(minSize,Math.min(maxSize,blockSize));切片主要由这几个值来运算决定
minsize:默认值:1
配置参数:mapreduce.input.fileinputformat.split.minsize
maxsize:默认值:Long.MAXValue
配置参数:mapreduce.input.fileinputformat.split.maxsize
blocksize
因此,默认情况下,切片大小= blocksize
maxsize(切片最大值):
参数如果调的比blocksize小,则会让切片变小,而且就等于配置的这个参数的值
minsize(切片最小值):
参数调的比blocksize大,则可以让切片变得比blocksize还大
-选择并发数的影响因素:
运算节点的硬件配置
运算任务的类型:     CPU密集型还是IO密集型
运算任务的数据量
-- map并行度的经验之谈
     如果硬件配置为212core + 64G,恰当的map并行度是大约每个节点20-100个map,最好每个map的执行时间至少一分钟。
如果job的每个map或者 reduce task的运行时间都只有30-40秒钟,那么就减少该job的map或者reduce数,每一个task(map|reduce)的setup和加入到调度器中进行调度,这个中间的过程可能都要花费几秒钟,所以如果每个task都非常快就跑完了,就会在task的开始和结束的时候浪费太多的时间。
     配置task的JVM重用可以改善该问题:
(mapred.job.reuse.jvm.num.tasks,默认是1,表示一个JVM上最多可以顺序执行的task数目(属于同一个Job)是1。也就是说一个task启一个JVM)
     如果input的文件非常的大,比如1TB,可以考虑将hdfs上的每个block size设大,比如设成256MB或者512MB
--ReduceTask并行度的决定
     reducetask





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值