MapReduce: 是一种分布式计算模型,主要用于搜索领域,解决海量数据的计算问题.
MapReduce:由两个阶段组成,Map和Reduce,用户只需要实现map()和reduce()两个函数,即可实现分布式计算,非常简单.
这两个函数的形参是key,value对,表示函数的输入信息
MapReduce原理***
在hadoop中,用于执行MapReduce的任务的机器有两个角色:
1.一是JobTracker,
a) 用于管理和调度工作,负责接收用户提交的作业,负责启动,跟踪任务执行.
b) JobSubmissionProtocl是JobClient与JobTracker通信的接口.
c) InterTrackerProtocol是TaskTracker与JobTracker通信的接口
2.二是TaskTracker,
a) 用于执行工作
MapReduce执行过程**
1.map任务处理:
a) 读取输入文件内容,解析成key,value对,对输入文件的每一行,解析成key,value对,每一个键值对调用一次map()函数.
b) 写自己的逻辑,对输入的key,value处理,转换成新的key,value输出.
c) 对输出的key,value进行分区.
d) 对不同分区的数据,按照key进行排序,分组,相同key的value放到一个集合中.
e) (可选)分组后的数据进行规约
2.reduce任务处理
a) 对多个map任务的输出,按照不同的分区,通过网络copy到不同的reduce节点.????????
b) 对多个map任务的输出进行合并,排序,写reduce函数自己的逻辑,对输入的key,value处理,转换成新的key,value,输出.
c) 把reduce的输出保存到文件中.
数据类型与格式***
Writable接口与序列化机制***
MapReduce的执行过程源码分析
序列化的概念
1.序列化:(Serialization): 是指把结构化对象转化为字节流
2.反序列化(Deserialization): 是序列化的逆过程,把字节流转回结构化对象
从0.20.2版本开始,Hadoop提供了新的API,不再向下兼容,新旧API的几个区别
1.在新的API中,Mapper与Reducer已经不是接口而是抽象类,而map函数和reduce函数已经不再实现Mapper和Reducer接口,而是继承Mapper和Reducer抽象类,这样做更加容易扩展,因为添加方法到抽象类中更加容易
2.新的API中更加广泛的使用了context对象,并使用MapContext进行MapReduce间的通信,MapContext同时充当OutputController,和Reporter角色,
3.Job的配置统一由Configuration来完成,而不必额外地使用JobConf对线程进行配置
4.由Job类来负责Job控制,而不是JobClient,Jobclient,JobClient在新的API中已经被删除.
API
1.Org.apache.hadoop.conf :定义了系统参数的配置文件处理API
2.Org.apache.hadoop.fs 定义了抽象的文件系统API
3.Org.apache.hadoop.dfs Hadoop分布式文件系统HDFS模块的实现
4.Org.apache.hadoop.,mapred : Hadoop分布式计算系统MapReduce模块的实现,包括任务的分发调度等,
5.Org.apache.hadoop.ipc 用在网络端和客户端的工具,封装了 网络一部I/O的基础模块
6.Org.apache.hadoop.io 定义了通用的I/O API,用于针对网络,数据库,文件等数据对象进行读写
Map处理:
Mapper处理的数据是由InputFormat分解够的数据集,其中InputFormat的作用是将数据集切割成小数据集InputSplit,每个InputSplit将由一个Mapper负责处理,此外,InputFormat中还提供了一个RecordReader的实现,并将一个InputSplit解析成<Key,Value>对提供给Map函数,InputFormat的默认值是TextInputFormat,它针对文本文件,按行将文本切割成InputSplit,并用LineRecordReader将InputSplit解析成键值对.
Reduce处理:
Map处理的结果会通过partition分发到Reducer,Reducer做完Reduce操作后,将通过OutputFormat输出结构,Mapper最终处理的结果键值对会被送到Reducer中进行合并,在合并的时候,有相同的key的键值对会被送到同一个Reducer上,Reducer是所有用户定制Reducer类的基类,它的输出是key及这个key所对应的所有value的一个迭代器,还有Reducer的上下文,Reducer处理的结果会通过Reducer.Context的writer方法输出到文件中.
负责的Map和Reduce函数:
1.setup函数:
a) Setup函数是在task启动开始就调用的,在 MapReduce中,作业会被组织成Map task和Reduce task, 每个task都以Map类或Reduce类为处理方法主体,输入分片为处理方法的输入,自己的分片处理完之后task也就销毁了,tsetup函数在task启动之后数据处理之前只调用一次,而覆盖的Map函数或Reduce函数会针对输入分片中的每个key调用一次,所以setup函数可以看做是task上的一个全局处理.
2.cleanup函数:
a) 与setup类似,在task销毁之前执行.
3.run函数:
a) 此函数是Map类或Reduce类的启动方法,先调用setup函数,然后针对每个key调用一次Map函数或Reduce函数,最后销毁task之前再调用cleanup函数.
MapReduce的工作机制:
1.MapReduce作业流程:
a) 在main函数中调用Job的启动接口,然后将程序提交到Hadoop上,MapReduce作业就可以在hadoop上运行.
b) 一个MapReduce作业的执行流程是: 代码编写->作业配置->作业提交->Map任务的分配和执行->处理中间结果->Reduce任务的分配和执行->作业完成.而在输入准备->任务执行->输出结果.
MapReduce作业的执行可以分为11个步骤:涉及4个独立的实体,它们在MapReduce执行过程中的主要作用是:
1.客户端(Client): 编写MapReduce代码,配置作业,提交作业
2.JobTracker:初始化作业,分配作业,与TaskTracker通信,协调整个作业的执行.
3.TaskTracker:保持与JobTracker的通信,在分配的数据片段上执行Map或Reduce任务,
4.HDFS:保存作业的数据,配置信息等,保存作业结果.
1. 提交作业
a) 作业提交需要配置的主要内容有:
i. 程序代码:这里主要值Map和Reduce函数的具体代码,
ii. Map和Reduce接口的配置:
iii. 输入输出路径:作业提交之前,还需要在主函数中配置MapReduce作业在hadoop集群上的输入路径和输出路径,(必须保证输出路径不存在)具体代码是:
1. FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
2. FileOutputFormat.addOutputPath(job, new Path(otherArgs[1]));
iv. 配置完作业的所有内容并确认后就可以运行作业了,
用户调用JobClient的runJob方法,在提交JobConf对象之后,runJob方法会先调用JobSubmissionProtocol接口定义的submitJob方法,将作业提交给JobTracker,紧接着,runJob不断循环,并在循环中调用JobSubmissionProtocol的getTaskCompletionEvents方法获取TaskCompletionEvent类的实例,了解作业的实体执行情况,如果发现作业运行状态有更新,就将状态报告给JobTracker.作业完成后,如果成功则显示作业计数器,否则将导致作业失败的错误记录到控制台.
b) Aa
2. 初始化作业
a) 在客户端用户作业调用JobTracker对象的submitJob()方法后,JobTracker会把词调用放入内部的TaskScheduler变量中,然后进行调度,默认JobQueueTaskScheduler, 也就是FIFO调度方式,当客户作业被调度执行时,JobTracker会创建一个代表这个作业的JobInProgress对象,并将任务和记录信息封装到这个对象中,以便跟踪任务的状态和进程.接下来JobInProgress对象的initTasks函数会对任务进行初始化操作..
b) Aa
3. 分配任务:
a) TaskTracker和JobTracker之间的通信和任务的分配是通过心跳机制完成的,TaskTracker作为一个单独的JVM执行一个简单的循环,主要实现每隔一段时间项Job发送心跳(Feartbeat): 告诉JobTracker此TaskTracker是否存在或,是否准备执行新的任务. JobTracker接收到心跳信息, 如果有待分配的任务,它就会为TaskTracker分配一个任务,并将分配信息封装在心跳通信的返回值中返回给TaskTracker,TaskTracker从心跳方法的ResPonse中得知此TaskTracker需要做的事,如果是一个新的Task,则将它加入本机的任务队列中,
b) Aa
4. 执行任务:
a) TaskTracker申请到新的任务之后,就要在本地运行任务了,运行任务的第一步就是将任务本地化(将任务运行所必需的数据,配置信息,程序代码从HDFS复制到TaskTracker本地),这主要是通过localizedJob()方法来完成的,这个方法通过以下几步来完成任务的本地化:
i. 将job.split复制到本地
ii. 将job.jar复制到本地
iii. 将job的配置信息写入job.xml
iv. 创建本地任务目录,解压job.jar;
v. 调用launchTaskForJob()方法发布任务
b) 任务本地化之后,就可以通过调用launchForJob()真正启动起来,接下来launchTaskForJob()又会调用launchTask()方法启动任务
i.
5. 更新任务执行进度和状态
a) MapReduce作业的进度有以下面几项组成:Mapper(或Reducer)读入或写出一条记录,在别走高中设置状态描述,增加计数器,调用Reporter对象的progress()方法/
b) 由MapReduce作业分割成的每个任务中都有一组计数器,它们对任务执行过程中的进度组成事件进行计数,如果任务要报告进度,它便会设置一个标志以表明状态变化将会发送到TaskTracker上,另一个监听线程检查到这个标志后,会告知Task当前的任务状态.
c) 同时,TaskTracker在每隔5秒发送给KobTracker的心跳中封装任务状态,报告自己的任务执行状态.
d) 通过心跳通信机制,所有TaskTracker的统计信息都会汇总到JobTracker处,JobTracker将这些统计信息合并起来,产生一个全局进度统计信息.
6. 完成作业:
a) 所有TaskTracker任务的执行进度信息都汇总到JobTracker处,当KobTracker接收到最后 一个任务的已完成通知后,便把作业的状态设置成为”成功”,然后JobClient也将及时得知任务已完成,最后从runJob()方法处返回(在返回后JobTracker会清空作业的工作状态,并指示TaskTracker也清空作业的工作状态,比如删除中间输出等)
作业调度机制:
在0.19.0版本之前,hadoop集群上的用户作业采用先进先出(FIFO)调度算法,即按照作业提交的顺序来运行,从0.19.0版本开始,Hadoop除了默认的FIFO调度器外,还提供了支持多用户同时服务和集群资源公平共享的调度器,即公平调度器(Fair Scheduler Guide) 和容量调度器(Capacity Scheduler Guide)
公平调度器:
公平调度是为作业分配资源的方法,其目的是随着时间的推移,让提交的作业获取等量的集群共享资源,让用户公平地共享集群,
具体做法是:当集群上只有一个作业在运行时,它将使用整个集群,当有其他作业提交时,系统会将TaskTracker节点空余时间片分配给这些新的作业,并保证每一个作业都得到大概等量的CPU时间.
公平调度按作业池来组织作业,它会按照提交作业的用户数目将资源公平地分割到这些作业池里,默认情况下,每一个用户拥有一个独立的作业池,以使每个用户都能获得一份等同的集群资源而不会管他们提交了多少作业,
在常规操作中,当提交一个新作业时,公平调度器会等待已运行作业中的任务完成,以释放时间片给新的作业,但公平调度器也支持作业抢占,.
最后,公平调度器还可以限制每个用户和每个作业池并发运行的作业数量.
Shuffle和排序
Map的输出会经过一个名为Shuffle的过程交给Reduce处理,当然,也有Map的结果经过sort-merge交给Reduce处理的.在 MapReduce流程中,为了让Reduce可以并行处理Map结果,必须对Map的输出进行一定的排序和分割,然后再交给对应的Reduce.而这个将Map输出进行进一步整理并交给Reduce的过程就成为了Shuffle.它是MapReduce的核心所在,shuffle过程的性能与整个MapReduce的性能直接相关.
总的来说,shuffle过程包含在Map和Reduce的两端中,在Map端的shuffle过程是对Map结果进行划分(partition), 排序(sort)和分割(spill),然后将属于同一划分的输出合并在一起(merge)并写到磁盘中, 同时按照不同的划分将结果发送给对应的Reduce(Map输出的划分与Reduce的对应关系由JobTracker确定), Reduce端又会将各个Map送来的属于同一个划分的输出进行合并(merge),然后对merge的结果进行排序,最后交给Reduce处理.