MapReduce 是 Google 推广的一个简单的编程模型,它对以高度并行和可扩展的方式处理大数据集很有用。 MapReduce 的灵感来源于函数式编程,用户可将他们的计算表达为 map 和 reduce 函数,将数据作为键值对来处理。 Hadoop 提供了一个高级 API 来在各种语言中实现自定义的 map 和 reduce 函数。
Hadoop 基础架构负责处理分布式处理的所有复杂方面:并行化、调度、资源管理、机器间通信、软件和硬件故障处理等等。 得益于这种干净的抽象,实现处理数百(或者甚至数千)个机器上的数 TB 数据的分布式应用程序从未像现在这么容易过,甚至对于之前没有使用分布式系统的经验的开发人员也是如此。
MR提交到集群后,会做如下操作:
备注:
MR将任务分割为 Map 端和 Reduce 端. 下图就是 Map/Reduce 过程图:
当你想更改map的个数的时候:
1). 通过更改配置文件中block的size来增大或者减小map的个数
2). 通过 JobConf's conf.setNumMapTasks(int num)
但是就算你设置了数目在这里,它在实际运行中的数目不会小于它实际分割产生的数目。意思就是当你通过程序设置map为2个,但是在读入数据的时候,分割数据是需要3个,那么最后任务在实际运行的过程中map个数是3个而不是你设置的2个
Map的个数是由任务本身的数据量决定的
当你想修改reduce的个数那么可以按照如下方法进行更改:
1). 在conf设置中调用conf.setStrings("mapred.reduce.tasks", values)
2). 调用job.setNumReduceTasks(tasks)
Reduce的个数hadoop是默认设置为1的,因为一个任务的输出的文件个数是由reduce的个数来决定的
在执行mapreduce之前,原始数据被分割成若干split,每个split作为一个map任务的输入
FileInputFormat: 所有以文件作为数据源的InputFormat实现的基类,它有2个功能:
SplitSize计算:
splitSize = max(minsize,min(maxSize,blockSize)) = 64M;
maxSize = mapred.max.split.size 默认最大值整数值
minSize = mapred.min.split.size 默认0
通过公式可以看出:
为什么默认分片大小与分块大小是相同的原因??
hadoop在存储有输入数据(HDFS中的数据)的节点上运行map任务,可以获得高性能,这就是所谓的数据本地化。所以最佳分片的大小应该与HDFS上的块大小一样,因为如果分片跨越2个数据块,对于任何一个HDFS节点(基本不肯能同时存储这2个数据块),分片中的另外一块数据就需要通过网络传输到map任务节点,与使用本地数据运行map任务相比,效率则更低
小文件问题:
如果一个文件的大小比block小,将不会被划分,所以每一个小文件都会被当做一个split并分配一个map任务,这也是Hadoop处理大文件的效率要比处理很多小文件的效率高的原因(10000个100kb的文件会被10000个map任务处理,肯定排队呀!
Shuffle描述着数据从map task输出到reduce task输入的这段过程
Shuffle 过程横跨 Map 和 Reduce 两端
在Hadoop这样的集群环境中,大部分map task与reduce task的执行是在不同的节点上。 当然很多情况下Reduce执行时需要跨节点去拉取其它节点上的map task结果。 如果集群正在运行的job有很多,那么task的正常执行对集群内部的网络资源消耗会很严重。 这种网络消耗是正常的,我们不能限制,能做的就是最大化地减少不必要的消耗。 还有在节点内,相比于内存,磁盘IO对job完成时间的影响也是可观的。从最基本的要求来说, 我们对Shuffle过程的期望可以有:
先看看map端的情况, 通过下图希望让大家清晰地了解从map数据输入到map端所有数据准备好的全过程:
下面我对细节来一一说明(注意红色圆数字):
通过MapReduce提供的Partitioner接口, Mapper 输出映射到 Reducer 上
确定 Reducer 后, 将数据写入'内存缓冲区'中,缓冲区的作用是批量收集map结果,减少磁盘IO的影响
***写入之前,key 与value 值都会被序列化成字节数组
本步骤会发生Spill, Sort, Combiner. 具体请见相应的部分~~~
当map task输出结果很多时。Map会将数据写入磁盘,保证缓冲区可以重复使用. 这个叫Spill(具体见'Spill')
当Spill时, MR程序默认会对写入内容按key排序, 然后合并(Combiner), 详情见'Combiner'
每次溢写会在磁盘上生成一个溢写文件, 如果map的输出结果真的很大就会生成多个溢写文件
当map task真正完成时,内存缓冲区中的数据也全部溢写到磁盘中形成一个溢写文件
故当map task真正完成时,会有一个或多个溢写文件,所以需要将这些溢写文件归并到一起,这个过程就叫做Merge
Merge过程中如果client设置过Combiner, 也会使用Combiner来合并相同的key
总结:
通过下图描述Reduce端的Shuffle细节:
下面我对细节来一一说明(注意红色圆数字):
Merge 有三种形式:
总结:
Mapper后的结果集该传递给哪个reduce去做下一步操作, 如何决定??? 答案就是通过MapReduce提供的Partitioner接口
它的作用就是根据key或value及reduce的数量来决定当前的输出数据最终应该交由哪个reduce task处理
Partition是shuffle的一部分
默认规则如下:
对key进行hash后,除以reduce task数量取模, 取模方式只是为了平均reduce的处理能力
如果用户自己对Partitioner有需求,可以订制并设置到job上
当map task输出结果很多时就可能发生内存溢出,所以需要在一定条件下将缓冲区的数据临时写入磁盘,然后重新利用这块缓冲区。这个从内存往磁盘写数据的过程被称为 Spill,中文可译为溢写
溢写是由单独线程来完成,不影响往缓冲区写map结果的线程
整个缓冲区有个溢写的比例(spill.percent), 这个比例 默认是0.8 ,故溢写线程启动时不应该阻止map的结果输出
当缓冲区的数据已经达到阈值时,溢写线程启动锁定这80%的内存,执行溢写过程。 Map task的输出结果还可以往剩下的20%内存中写,互不影响
在 Spill 过程中, MR程序会将数据按key合并到一块,这个过程叫reduce也叫combine
但MapReduce的术语中,reduce只指reduce端执行从多个map task取数据做计算的过程。除reduce外,非正式地合并数据只能算做combine了
注意:非正式地合并叫combine,其实大家知道的,MapReduce中将Combiner等同于Reducer
感激: https://blog.csdn.net/zengxiaosen/article/details/73189207 的文章