MapReduce理论
MapReduce
-map-->映射
-reduce-->归纳
-mapreduce必须构建在hdfs之上
-mapreduce是一种离线计算框架
-在线:实时数据处理
-离线:数据处理时效性没有在线那么强,但是相对也需要很快得到结果
-mapreduce不会马上得到结果,他会有一定的延时
-如果数据量小,使用mapreduce反而不合适,就像用原子弹去打蚊子
-原始数据-->map(Key,Value)-->Reduce
MR设计理念
-分布式计算
-将大的数据切分成多个小数据,交给更多的节点参与运算
-计算向数据靠拢
-将计算传递给有数据的节点上进行工作
MR的计算流程
-计算1T数据中每个单词出现的次数 → wordcount
1.Map
1.1 原始数据
-1T数据被切分成块存放在HDFS上,每一个块有128M大小
1.2 数据块
-hdfs上数据存储的一个单元,同一个文件中块的大小都是相同的
-因为数据存储到HDFS上不可变,所以有可能块的数量和集群的计算能力不匹配
-我们需要一个动态调整本次参与计算节点数量的一个单位
-我们可以动态的改变这个单位 参与的节点
1.3 切片Split
-切片是一个逻辑概念
-通过切片的大小可以达到控制计算节点数量的目的
-一般切片大小为Block的整数倍(2 1/2)
-如果Split>Block ,计算节点少了
-如果Split<Block ,计算节点多了
-默认情况下,Split==Block
-一个切片对应一个MapTask
1.4 MapTask(map任务)
-map默认从所属切片读取数据,每次读取一行到内存中
-我们可以根据自己书写的分词逻辑(空格分隔).计算每个单词出现的次数
-这时就会产生 (Map<String,Integer>)临时数据,存放在内存中
-但是内存大小是有限的,如果多个任务同时执行有可能内存溢出(OOM)
-如果把数据都直接存放到硬盘,效率太低
-我们需要在OOM和效率低之间提供一个有效方案
-可以先在内存中写入一部分,然后写出到硬盘
1.5 分区Partation
-根据Key直接计算出对应的Reduce
-分区的数量和Reduce的数量是相等的
-hash(key) % partation = num
1.6 排序Sort
-对要溢写的数据进行排序(QuickSort)
-按照先Partation后Key的顺序排序 → 相同分区在一起,相同Key的在一起
-我们将来溢写出的小文件也都是有序的
1.7 溢写Spill
-在内存中构建一个环形数据缓冲区(kvBuffer),默认大小为100M
-设置缓冲区的阈值为80%,当缓冲区的数据达到80M开始向外溢写到硬盘
-溢写的时候还有20M的空间可以被使用 效率并不会被减缓
-而且将数据循环写到硬盘,不用担心OOM问题(数据溢出)
1.8 合并Merge
-因为溢写会产生很多有序的小文件,而且小文件的数目不确定
-后面向reduce传递数据带来很大的问题
-所以将小文件合并成一个大文件,将来拉取的数据直接从大文件拉取即可
-合并小文件的时候同样进行排序(归并排序),最终产生一个有序的大文件
2. Reduce
2.1 拉取Fetch
-我们需要将Map的临时结果拉取到Reduce节点
-原则:
-相同的Key必须拉取到同一个Reduce节点
-但是一个Reduce节点可以有多个Key
-拉取数据的时候必须对Map产生的最终的合并文件做全序遍历
-而且每一个reduce都要做一个全序遍历
-如果map产生的大文件是有序的,每一个reduce只需要从文件中读取自己所需的即可
Object的hashCode()—equals()
如果两个对象equals,那么两个对象的hashcode一定相等
如果两个对象的hashcode相等,但是对象不一定equlas
2.2 合并Merge
-因为reduce拉取的时候,会从多个map拉取数据
-那么每个map都会产生一个小文件,这些小文件(文件与文件之间无序,文件内部有序)
-为了方便计算(没必要读取N个小文件),需要合并文件
-归并算法合并成 1个(其实是两个)
-相同的key都在一起
2.3 归并Reduce
-将文件中的数据读取到内存中
-一次性将相同的key全部读取到内存中
-直接将相同的key得到结果 → 最终结果
2.4 写出Output
-每个reduce将自己计算的最终结果都会存放到HDFS上