Hadoop--map-reduce原理

MapReduce的作业(job)是由客户端提交给Hadoop集群的。一个job包括了输入数据,MapReduce程序和配置信息。Hadoop将作业非为若干个任务(task)来执行,其中包括map任务和reduce任务。

有两类节点和task的执行相关,一类是jobtracker,另外一类是tasktracker。

jobtracker通过调度tasktracker上运行的任务来协调所有运行在系统上的作业。

tasktracker在运行任务的同时将运行的进度返回给jobtracker,jobtracker由此记录每项作业的情况,如果有tasktracker执行任务失败,则jobtracker可以在另外一个tasktracker上重新调度失败的任务。

Hadoop将MapReduce的输入数据划分成等长的数据块,被称为输入分片。hadoop为每个分片构建一个map任务,并该任务运行由用户定义的map函数对分片中的每条记录。

对于大部分作业来说,一个合理的分片大小趋向于HDFS的一个块大小。

Hadoop在存储有输入数据的节点上运行map任务,可以获得最佳性能(数据本地化优化)。

这就是最佳分片大小与HDFS块大小相同的原因:因为他是确保可以存储在单个结点上的最大输入块大小。如果分片跨两个数据库,那么对任何一个HDFS节点,基本上都不可能同时存储这两个数据库,因此分片中的部分数据需要通过网络传输到Map任务节点。与使用本地数据运行整个map相比,就显得笨拙了。

map-reduce的运行流程:

Hadoop--map-reduce原理_第1张图片

  1. map-reduce 程序启动作业
  2. jobclient向jobTracker请求一个新的jobId。同时检查作业输入和输出说明。如果不合法就返回异常
  3. jobclient将运行作业所需要的资源复制到一个以作业ID命名的目录下jobtracker的文件系统中。作业jar的副本较多,因此在运行作业的任务时,集群中有很多副本可供taskTracker访问。
  4. jobclient告知jobTracker作业准备执行
  5. jboTracker接收到对其submitJob()方法的调用后,会把此调用放入一个内部队列中,交由作业调度进行调度,并对其初始化。
  6. 为了创建任务运行列表,作业调度器首先从共享文件系统中获取jobClient以计算好的输入分片信息,然后为每一个分片创建map任务。创建reduce任务数量由jobConf的mapred.reduce.task属性决定.然后调度器创建相应数量的要运行的reduce任务。任务在此时被指定ID
  7. tasktracker运行一个简单的循环来定期发送“心跳”给jobtracker,用来告诉jobtracker它自己是否还存活和是否准备好运行新的任务。如果是,jobtracker会为他分配一个任务,并使用“心跳”返回值与tasktracker进行通信。

在为tasktracker选择任务(task)之前,jobtracker首先要选定任务所在的作业(job)。选择好作业之后jobtracker就可以作为该作业选定一个任务。对于map任务和reduce任务,tasktacker有固定数量的任务槽。eg:一个tasktracker可能同时运行两个map任务和reduce任务。默认调度器在处理reduce任务之前会填满空闲的map任务槽。因此,如果tasktracker至少有一个空闲的map任务槽,jobtracker会为它选择一个map任务,否则选择一个reduce任务。

在选择reduce任务的时候,jobtracker简单的从待运行的reduce任务列表中选取下一个来执行,用不着考虑数据的本地化。对于一个map任务jobtracker会考虑tasktracker的网络位置,并选取一个距离与其输入分片最近的tasktracker。最理想的情况是 数据本地化的(任务运行在和输入分片在同一个机器上)。次之是 机架本地化的。

tasktracker执行任务:通过共享文件系统把作业的jar文件复制到tasktracker所在的文件系统,从而实现作业的jar文件本地化,同时,tasktracker将应用程序所需要的全部文件从分布式缓存复制到本地磁盘。然后tasktracker为任务新建一个本地工作目录,并把jar文件中的内容解压到这个文件夹下,然后tasktracker新建一个TaskRunner实例来运行该任务。TaskRunner启动一个新的JVM来运行每个任务,以便用户自定义的map和reduce函数的人和问题不会影响到tasktracker。子进程通过接口与父进程通信。任务的资进程每隔几秒便告知父进程它的进度,直到任务完成。

当jobtracker收到作业的最后一个任务已完成的通知后,便把作业状态设置为“成功”。然后在jobclient查询状态时直到任务已经完成。于是jobclient打印一条消息告知用户,然后从runJob方法返回。
最后jobtracker清空作业的工作状态,指示tasktracker也清空作业的工作状态(eg:删除中间输出)。

map任务将结果写入本地硬盘,而非HDFS。因为map任务的结果是中间结果,要给reduce任务进行再次处理,处理完之后map任务的结果就没有价值了,通常是被删掉。HDFS上的同一份数据,通常情况下是要备份的。如果存入HDFS,那么就有些小题大做了。

MapReduce确保每个reducer的输入都按键排序。系统执行排序的过程—将map输出作为输入传给reducer,称之为shuffle。

Hadoop--map-reduce原理_第2张图片

map产生结果之后会先在内存中,过了一定的量之后开始写入本地硬盘。

写入磁盘之前,线程先根据数据最终要送到的reducer把数据划分成相应的分区(partition)。在每个分区中,后台线程按键进行行内排序,如果有一个combiner,它会在排序后的输入上运行。
一旦缓冲区达到阈值,就开始新建溢出文件。所以在map任务写完其最后一个输出记录之后,会有几个溢出写文件。在溢出写文件被合并成一个已经分区且排序出的输出文件。

combiner的意义在于让写入本地磁盘和传到reducer上的数据更加紧凑。

reducer通过http方式得到输出文件的分区。map输入文件位于运行map任务的tasktracker的本地磁盘上。现在,tasktracker需要为分区文件运行reduce任务。这个reduce任务通常需要集群上若干个map任务的输出作为其特殊的分区文件。每个map任务完成时间可能不同。因此只要有一个任务完成,reduce任务就开始复制其输出。如果map输出相当小,则会被复制到 reduce tasktracker的内存中,否则会被复制到磁盘。一旦内存缓冲区达到阀值大小或者达到map输出阀值,则合并后溢出写到磁盘中。随着磁盘上的副本增多,后台线程会将他们合并为更大,排好序的文件。为后边的合并节省一些时间。复制完所有map输出被复制期间,reduce任务进入合并阶段。这阶段将合并map输出,维持其顺序排序。

在reduce阶段,对已排序输出中的每个键都调用reduce函数。此阶段的输出直接写到HDFS中。

你可能感兴趣的:(java高级-大数据知识,mapreduce)