MapReduce原理
1. MapReduce核心思想


1.1 分而治之
- 把一个复杂的问题,按照一定分解的方法,分为等价的规模较小的若干部分,然后逐个解决,分别找出个部分的结果,把各部分的结果组成整个问题的结果。
1.2 总结与思考⭐
1)MR的核心思想,分而治之,把一个复杂的问题,按照一定分解的方法,分为等价的规模较小的若干部分,然后逐个解决,分别找出个部分的结果,把各部分的结果组成整个问题的结果
2. MapReduce


2.1 Map阶段
- 将任务分解,把复杂任务分解成若干简单的任务,并行处理,前提是这些任务没有必然的依赖关系,可以单独执行任务
2.2 Reduce阶段
- 负责将任务合并,把map阶段的结果进行全局汇总
2.3 总结与思考⭐
1)MR程序分为Map-Shffule-Reduce阶段,Map任务分解,Shffule洗牌排序,Reduce任务合并
3. MapReduce编程模型

3.1 键值对转换
- 整个mapreduce的过程就是整个键值对转换的过程



3.2 多个MapReduce任务

3.3 总结与思考⭐
1)MR编程模型,用于处理大规模并行计算(MPP)
2)MR数据流模型

3)MR可能不需要Reduce任务
4. MapReduce编程实例
4.1 词频统计

## k1 v1
<0,Hello World>
<12,Hello Hadoop>
## 0,12表示偏移里量
## k2 v2
<Hello 1>
<World 1>
## 1,1表示数据量
##k3 v3
<hadoop 2>
<hello 3>
##2,3表示数据统计量
## 整个mapreduce的过程就是整个键值对的转换
4.2 总结与思考⭐
1)文件内容--TextInputFormat--><k1,v1>--MAP--><k2,v2>--shffule洗牌-Reduce-><k3,v3>
5. MapReduce工作过程⭐⭐⭐⭐⭐


5.1 分片 / 格式化数据源

## 1. 将源文件进行拆分成分片(split),拆分成(Hadoop2.x 默认是128M),每一个分片(split)就是一个map任务,每一个map任务都会执行一个map函数,map函数处理分片里的每一条记录;
## 2. 将划分好的分片(split)格式化成键值对,key代表偏移量,value代表每一行内容
5.2 执行MapTask

## 1. 每个map任务都有一个内存缓冲区(缓冲区大小100M)
## 2. 经过map任务处理的中间结果会进入缓冲区
## 3. 如果写入的数据达到阀值(80M),则会启动一个线程将内存溢出的数据写入磁盘(剩下20M留给中间结果继续写入)
## 4. 溢写过程中,MapReduce框架会对Key进行排序
## 5. 中间结果较大,会形成多个溢写文件,最后缓冲区数据也会全部溢写如磁盘形成一个溢写文件
## 6. 如果是多个溢写文件,最后会合并成一个文件
5.3 执行shuffle过程

## map阶段数据传递给reduce阶段,这个过程叫做shuffle
## shuffle会将mapTask输出的处理结果数据,分发给reduceTask,并在分发过程中,对数据按key进行分区和排序

5.4 执行ReduceTask

## 输入ReduceTask的数据流是<key,{value list}>
## reduce()方法进行逻辑处理,再以<key,value>的形式输出
5.5 写入文件

## MapReduce框架会将RedcueTask生成的<key,value>传入OutoutFormat的write方法中,实现文件的写入

## 一般情况下,一个block(物理分片)对应一个split(逻辑分片),一个split(分片)对应一个maptask
## 每一个split会格式化为<k1,v1>的键值对
## <k1,v1>经过mapTask转换为<k2,v2>
## <k2,v2>经过shuffle(Group)转换为<k2,{v2,.....}>
## <k2,{v2,.....}>经过Reduce转换为<k3,v3>
5.6 总结与思考⭐
MR工作过程;参考图片:/home/fubo/OneDrive/笔记/理论知识⭐/大数据原理/离线批处理/34247528fa3340968c5fa58d73b31b34.png
1)分片 / 格式化数据源;拆分为split(默认128M),一个split对应一个map;格式化split,生成<k1,v1>,key代表偏移量,value代表每一行内容
2)执行MAPTASK;MAP任务会对SPLIT进行加工处理,生成<k2,v2>
3)Shuffle阶段(溢写,归并);对<k2,v2>进行排序,文件的拆分合并;参考⭐⭐:https://blog.csdn.net/weixin_42322454/article/details/128400205
将结果存入内存缓冲区(默认100M)中,超过阈值(80M)或完成计算,会溢写成一个文件,溢写的过程会对key进行排序,并对溢写的进行拆分合并(合并排序,一是分区内的合并同分区,并排序;二是不同溢写文件的,合并文件并排序),所以这个过程可能会因为key值发生数据倾斜
4)执行ReduceTask;将<k2,v2>转换为<k3,v3>
5)写入文件;将<k3,v3>传入OutPutFormat的write方法
6)整体路程参考下图

6. MapTask工作原理⭐⭐⭐⭐⭐

6.1 Read阶段

## read阶段:MapTask通过用户编写的RecordReader,从输入的InputSplit中解析出一个个key/value(即<k1,v1>)
## 一般情况下,会把一行数据转换成一个键值对
6.2 Map阶段

## map阶段:将解析出的key/value交给用户编写的map()函数处理,并产生一系列新的键值对即(<k2,v2>)
6.3 Collect阶段(shffule)

## collect阶段:在用户编写的map()函数中,数据处理完成后,会调用outputCollector.coolect()输出结果
## outputCollector.coolect()函数会将<k2,v2>(通过调用partitioner),写入一个环形内存缓冲区(默认100M)
6.4 Spill阶段(shffule)

## Spill阶段:溢写阶段,环形缓冲区达到80M后,MapReduce会将数据写到本地磁盘上,生成一个临时文件
## 写入本地磁盘前,会对数据进行一次本地排序,并在必要时对数据进行合并/压缩
6.5 Combine阶段(shffule)

## Conbie阶段:当所有处理完成后,mapTask对所有临时文件进行一次合并,确保最终只生成一个数据文件
6.6 总结与思考⭐
1)READ阶段;读取split
2)map阶段;<k1,v1>转换为<k2,v2>
3)Collect/Spill/Combine(map阶段的shuffle);参考⭐⭐:https://blog.csdn.net/weixin_42322454/article/details/128400205
7. ReduceTask工作原理⭐⭐⭐⭐⭐


7.1 Copy阶段(shffule)

## Copy阶段:Reduce会从各个MapTask上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定阀值,则写到磁盘上,否则直接放入内存中
7.2 Merge阶段(shffule)

## Merge阶段:在远程拷贝数据的同时,ReduceTask会启动两个后台线程,分别对内存和磁盘上的文件进行合并,以防止内存使用过多或者磁盘文件过多
7.3 Sort阶段(shffule)

## 用户编写reduce()方法输入数据是按key进行聚集的一组数据。
## 为了将key相同的数据聚在一起,Hadoop采用了基于排序的策略。
## 由于各个MapTask已经实现对自己的处理结果进行局部排序,因此,ReduceTask只需对所有数据进行一次归并排序即可。
7.4 Reduce阶段

## Reduce阶段:对排序后的键值对调用reduce()方法,键相等的键值对调用一次reduce()方法
## 每次调用会产生0个或者多个键值对
## 最后把输出的键值对写入到HDFS系统中
7.5 Write阶段

## Write阶段:reduce()函数将计算结果写到HDFS上

## 1. copy阶段,将map结果拉取到memoryBuffer(缓存)中,然后对这些数据进行合并
## 2. 超过内存一定阀值时,则会写入到磁盘,也会对磁盘上的文件作一些合并
## 3. 对内存和磁盘中的文件再做一次合并,合并时会作一次排序
## 4. 再将排序后的数据交给ReduceTask
## 5. ReduceTask将结果输出写入到hdfs文件上
7.6 总结与思考⭐
1)Copy/Merge/Sort(reduce阶段的shuffle);数据的拉取,合并,排序;参考⭐⭐:https://blog.csdn.net/weixin_42322454/article/details/128400205
2)Reduce阶段,将<k2,v2>转换为<k3,v3>
3)Write阶段,将结果<k3,v3>写入到HDFS上
8. Shuffle工作原理⭐⭐⭐⭐⭐

8.1 Map阶段的Shuffle

## 1. MapTask处理的结果会放入缓冲区中(该缓冲区默认大小为100M),当缓冲区要溢出时(默认达到缓冲区80%),会在本地文件系统创建一个溢出文件,将该缓冲区的数据写入到这个文件
## 2. 写入磁盘之前,线程会根据reduceTask数量,对数据分区,一个reduce任务对应一个分区的数据。这样做是为了避免有些reduce任务分配到大量数据,而有些reduce任务分到很少的数据(数据倾斜)
## 3. 数据分区,即给<k2,v2>的键值对打上标记
## 4. 分完数据后,会对每个分区的数据进行排序,如果设置了Combiner,将排序后的结果进行combiner操作
## 5. 在map任务输出最有一个记录时,可能有很多溢出小文件,需要对溢出的小文件进行合并,合并的过程中,会进行排序和combine操作
## 6. 其目的有两个:一是尽量减少每次写入磁盘的数据量;二是尽量减少下一复制阶段网络传输的数据量。最后合并成一个已分区且已排序的文件
## 7. 将分区中的数据拷贝给对应(分区的标记)的reduce任务
## 1. mapTask任务结果---》缓存区---》多的溢出到文件
## 2. 线程进行数据分区(给每一个分区打上标记,分到对应的ReduceTask) 排序 合并
## 3. 最后合并成一个已分区且已排序的文件
8.2 Reduce阶段的Shuffle

## 1. Reduce任务接受到不同map任务传来的数据,并且每个map传来的数据都是有序的。
## 2. 如果reduce任务接收的数据量相当小,则直接存储到内存中,如果数据量超过了该缓冲区大小的比例,则对数据合并后溢写到磁盘中
## 3. 随着溢写文件增多,后台线程会将它们合并成一个更大有序的文件,给后面的合并节省了时间
## 4. 合并的过程会产生许多中间文件,但MapReduce会让写入磁盘的数据尽可能的少,并且最后一次合并的结果并没有写入磁盘,而是直接输入到reduce函数
## 1. 拉取mapTask结果
## 2. 合并 排序 输出
8.3 总结与思考⭐
1)Shuffle的重要性:是mapreduce的核心,其性能直接决定MR的性能;参考⭐⭐:https://blog.csdn.net/weixin_42322454/article/details/128400205
2)MAP阶段的Shffule

3)Reduce阶段的Shffule

9. MapReduce的编程组件⭐⭐⭐⭐⭐

9.1 InputFormat组件


InputFormat组件的两个功能
1. 数据切分,切分成若干split,每个split对应一个mapTask ----> getSplits方法
2. 数据格式化,将split解析成键值对<k1,v1> ----> createRecordReader方法





long splitSize = computeSplitSize(blockSize, minSzie, maxSize)
protected long computeSplitSize(long blockSize , long minSize, long maxSize){
return Math.max(minSize, Math.min(maxSize, blockSize));
}
9.2 Maper组件


9.3 Reducer组件






key --> k2 --> "hello"
value --> {v2,....} --> "1,1"
9.4 Partitioner组件



int ---分区编号
key --- k1
value --- v1
numPartitions -- reduce任务数

HashPartitioner

key相同,就会被分到同一个reduce任务
分区的目的,是希望map结果能均匀分配到reduce任务中,避免数据倾斜
9.5 Combiner组件

Combiner组件其实就是继承的reduce类
reduce是对整体的计算结果作整体的汇总
而Combiner则是对局部结果作一次汇总



Combiner组件从某种程度上,是对mapreduce任务的优化,有没有输出结果都一样
9.6 OutputFormat组件


常用的:TextOutputFormat<K,V>
9.7 总结与思考⭐
1)InputFormat组件:将文件拆分为split,并格式化为<k1,v1>;split大小由minzise,maxsize,blocksize共同决定
2)Maper组件:map方法对应map任务
3)Reduce组件:reduce方法对应reduce任务,整体的计算结果的汇总
4)Partitioner组件:在map-shffule阶段开始,给<k2,v2>添加分区,之后根据分区分配到不同的reudce任务中
5)Combiner组件:对局部数据的汇总,是对reduce类的重写
6)OutputFormat组件:将结果写入HDFS
10. MapReduce的运行模式


10.1 本地模式
wordcount代码,本地建立input数据源,output文件夹
直接运行WordCountDrive代码即可




10.2 集群运行模式

上面的本地路径要修改为HDFS路径
10.3 总结与思考⭐
1)集群运行模式:将MR程序编译成jar包提交至Yarn集群,Yarn进行资源管理和调度,将程序分发到不同节点并执行,处理的数据结果都在HDFS文件系统中
11. MapReduce性能优化策略

11.1 数据输入

使用CombineTextInputFormat作为输入,解决输入端大量小文件的场景
11.2 Map阶段

## 通过设置以下两个参数,减少spill溢写次数,从而减少磁盘IO
io.sort.mb --> 环形缓冲区大小,默认100M
sort.spill.percent --> 环形缓冲区溢写的比例,默认80%
## 增大merge的文件数目
io.sort.factor --> 增大merge的文件数目,减少merge次数,默认是10个
## 加入combine处理
min.num.spill.for.combine 运行combiner时,所需的最少溢出文件数,默认3


11.3 Reduce阶段


11.4 Shuffle阶段

11.5 其他属性调优


11.6 总结与思考⭐
1)数据输入阶段:将小文件合并,减少map任务数量,使用CombineTextInputFormat输入
2)Map阶段:减少spill(io.sort.mb,sort.spill.percent),merge次数(io.sort.factor),进行combine处理(min.num.spill.for.combine);

3)Reduce阶段:合理设置reduce/map任务数量;设置map/reduce共存;规避reduce;设置reduce的buffer

4)Shuffle阶段:给Shuffle提供更多的内存空间

5)其他属性调优

12.经典案例
12.1 MapReduce经典案例-倒排索引(待学习)

倒排索引是文档检索系统中最常用的数据结构,被广泛应用于全文搜索引擎。
倒排索引主要用来存储某个单词(或词组)在一组文档中的存储位置的映射,提供了可以根据内容来查找文档的方式,而不是根据文档来确定内容,因此称为倒排索引。
带有倒排索引的文件,我们称为倒排索引文件,简称为倒排文件














11.6 总结与思考⭐
浙公网安备 33010602011771号