MapReduce简介
Hadoop MapReduce是一个软件框架,基于该框架能够容易地编写应用程序,这些应用程序能够运行在由上千个商用机器组成的大集群上,并以一种可靠的,具有容错能力的方式并行地处理上TB级别的海量数据集。
MapReduce是一种分布式计算模型,是Google提出的,主要用于搜索领域,解决海量数据的计算问题。
MR有两个阶段组成:Map和Reduce,用户只需实现map()和reduce()两个函数,即可实现分布式计算。
Hadoop四大组件
首先让我们来重温一下 hadoop 的四大组件:
HDFS:分布式存储系统
MapReduce:分布式计算系统
YARN: hadoop 的资源调度系统
Common: 以上三大组件的底层支撑组件,主要提供基础工具包和 RPC 框架等
Mapreduce 是一个分布式运算程序的编程框架,是用户开发“基于 hadoop 的数据分析 应用”的核心框架
Mapreduce 核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的 分布式运算程序,并发运行在一个 hadoop 集群上
MapReduce的思想
主要思想:分而治之,分久必合
核心思想:相同的key为一组,调用一次reduce方法,方法内迭代这一组数据进行计算
(1)Mapper负责“分”,即把复杂的任务分解为若干个“简单的任务”来处理。“简单的任务”包含三层含义:
一是数据或计算的规模相对原任务要大大缩小;
二是就近计算原则,即任务会分配到存放着所需数据的节点上进行计算;
三是这些小任务可以并行计算,彼此间几乎没有依赖关系。
(2)Reducer负责对map阶段的结果进行汇总。至于需要多少个Reducer,用户可以根据具体问题,通过在mapred-site.xml配置文件里设置参数mapred.reduce.tasks的值,缺省值为1。
MapReduce的工作机制
shuffle write阶段
1,block ≈split切片=map task
默认buffer的大小是100M
2,map task将处理后每一条记录打上标签,上标签的目的就是为了让这一条知道将来被哪一个reduce task处理
打标签:分区
分区是由分区器来完成的
默认的分区器:HashPartitioner
分区策略:根据key的hashcode与reduce task Num 取模
3,进入buffer之后的每一条记录是由三部分组成的:
①分区号
②key
③value
4,溢写过程:
portitions=combinner->sort->spill
即=小聚合+排序+归并
map task 一条条的往buffer中去写,一旦写入到80M,此时他将会把这80M的内存进行封锁,封锁后会对内存中的数据进行combiner(小聚合)。
排序:分区号、key
将相同分区号的数据放在一起,并且对分区内的数据进行排序
以上的combiner以及排序完成后,就开始溢写数据到磁盘上
此时的磁盘文件就是根据分区号分好区的,并且是内部有序的文件。
注意:没进行一次溢写就会产生一个小的磁盘文件。
5,归并
map task计算完毕后,会将磁盘上的小文件合并成一个大文件,在合并的时候会使用归并排序的算法,将各个小文件合并成一个有序的大文件
每一个map task都会经过刚才所说的一切,也就是每一个map task都会产生一个有分区的并且有序的大文件。
shuffle read阶段
去map端读取相应的分区数据,将分区数据写入到内存中,内存满了就会溢出,溢出之前会排序,当把所有的数据取来之后,会将溢出产生的磁盘小文件合并,排序成有序的大文件。
why要合并产生一个有序的大文件?
原因:就是为了提高分组的分组效率
归根来说,这四次排序都是为了提高分组的分组效率。
最后每一组数据再调用一次reduce函数,产生结果,此时reduce要处理的文件,经过前三次的排序,内部都是有序的,且经过合并,文件的数量也大大减少,所以极大地加快了最后reduce函数排序的过程。
MapReduce的计算框架
hadoop 1.0版本
jobTracker的作用:
1,负责资源调度 主节点 一旦故障 整个集群瘫痪了
2,负责任务调度,主节点
问题:
1,负载过高,容易故障
2,与MR的耦合度太高,如果spark也要运行在这套框架上,需要自己去实现,这个集群就存在两套资源调度器,就会出现资源隔离问题以及资源抢夺问题。
这种设计模式,jobTracker既做资源调度,又做任务调度,这样就会造成job的压力很大,一旦jobTracker节点挂掉,整个计算框架就挂了,归根结底还是单点故障问题。
除此之外,如果当jobTracker分配资源任务的时候,又来了一个application应用请求计算框架分配资源,这个时候就会出现资源隔离和资源抢夺问题。
hadoop 2.0之后版本
hadoop 2.0之后采用yarn集群来进行资源调度分配
大体流程:
1,client拿到Application计算文件的路径找到NN获取每一个block的位置
2,找到RM为ApplicationMaster申请资源
3,RM接受客户端的申请,然后查看哪一个节点上的资源充足,如果大部分节点的资源充足,那就随机找一台节点启动contain容器。
4,在node01处规划一个container以后,MM会在这个容器中启动一个ApplicationMaster(主要负责任务调度)
5,client会将生成的报表交给AM
6,AM拿到报表后会根据报表去找RM申请资源
7,AM分发map task到各个yarn-child中执行
8,最后经过map task会产生一个个携带分区号,内部有序的磁盘小文件。
优点:
这种方式,把资源调度和任务调度分开,在不同节点上进行,这样极大地减轻了单节点的负担,故障发生的概率也相对的减少了。
此外把applicationMaster放到随机的一个datenode节点,因为本身节点就存储了一部分数据,所以又可以减少网络IO。
还有就是为了解决资源调度器的单调故障问题,我们又采用zookeeper集群的形式,对其做监管和备份,一旦RM挂掉,就会立即启动备份的RM.
MapReduce的框架的优点
- 易于编程,用户通常情况下只需要编写Mapper和Reducer程序即可。
- 良好的扩展性,即可以很容易的增加节点
- 高容错性,一个Job默认情况下会尝试启动两次,一个mapper或者reducer默认会尝试4次,如果一个节点挂了,可以向系统申请新的节点来执行这个mapper或者reducer
- 适合PB级别的数据的离线处理
MapReduce编程模型
Map阶段:
- 输入数据的解析:InputFormat
- 输入数据处理:Mapper输入数据处理:Mapper
- 输入分组:Partitioner输入分组:Partitioner
- 本节点的规约:Combiner ,本节点的规约:Combiner ,
Reduce阶段:
- Shuffling阶段拉取数据
- 排序,溢写
- Reducer数据规约:Reducer
- 数据输出格式: OutputFormat
详细介绍:
InputFormat
将文件进行分片,InputSplit方法,处理跨行问题
将分片数据解析成key/val 对,默认实现是TextInputFormat,其中key是句柄偏移量,value是行内容
关于Split和Block的解释
默认情况下Split就是HDFS中的一个Block,但是用户可以自定义Split与Block的对应关系,split切片是逻辑
上的切,并没有真正的去切割数据。
理解Partitioner
Partitioner决定了Mapper的每条输出数据交由那个Reduce程序进行处理,默认情况下是通过
hash(key)mode R
R 是 Reduce Task 的数目
Map函数与Reduce函数:
函数 | 输入 | 输入 | 说明 |
---|---|---|---|
Map | <“k1”,v1> 如:<行号,”a b c”> | List(<"k2,"v2>) 如:<“a”,1> <“b”,1> <“c”,1> | 1.将小数据集进一步解析成一批<key,value>对,输入Map函数中进行处理 2.每一个输入的<"k1,v1>会输出一批<k2,v2>。<k2,v2>是计算的中间结果 |
Reduce | <k2,List(v2)> 如:<“a”,<1,1,1>> | <k3,v3><“a”,3> | 输入的中间结果<k2,List(v2)>中的List(v2)表示是一批属于同一个k2的value |
问题:
Yarn下的mapper和reducer并发执行个数由什么决定的呢?
由调度的资源决定的,也就是说启动的YarnChild个数多少取决于资源的分配和free的资源量
map个数主要由任务切片spilt决定的,默认情况下一个split的大小就是block由参与任务的文件个数决定的。
分区与分组的概念
分区的目的是根据Key值决定Mapper的输出记录被送到哪一个Reducer上去处理。而分组的就比较好理解了。分组就是与记录的Key相关。在同一个分区里面,具有相同Key值的记录是属于同一个分组的。
默认情况下key值相同为一组,但也可以自定义分组,比如我们天气的例子:找出一个月中温度最高的两天,我们分组就是按照年和月进行分组的,同一年同一月的为一组。