看过视频以及网上的解释,总是不是特别清楚MapReduce的工作原理,只有这本书能帮到我了。四级水平第一次翻译国外书籍,见谅。

Hadoop权威指南第4版英文版下载地址:http://pan.baidu.com/s/1ntxj9RN


hadoop权威指南这本书 hadoop权威指南4中文版pdf_hadoop权威指南这本书

Job提交

在Job上的submit()方法创建一个内部JobSubmitter实例并且调用submitJobInternal()在它里面(步骤1)。当提交Job之后,如果在最后一次报告后它发生变化那么waitForCompletion()每秒调查一次Job的进展并且向控制台报告这个进展。当Job成功完成,Job计数器被显示。否则,造成Job失败的错误会被记录在控制台上。

Job Submission过程被JobSubmitter按如下方式执行:

·向RM(resource manager)申请一个新的应用ID,为MR(MapReduce)的ID使用。

·检查Job Submission的输出描述。例如,如果输出目录没有被指定或者已经存在,那么Job Submission将不会被提交并且一个错误将会被扔到MR程序。

·计算这个Job的输入切片。如果切片不能被计算(可能因为输入路径不不存在),Job不会被提交并且一个错误将会被扔到MR程序。

·复制需要运行这个Job的资源,包括Job的JAR文件,配置文件,和已经被计算的输入切片到公共文件系统的用JobID命名的目录中(步骤3)。Job的JAR根据一个因素被拷贝(被mapreduce.client.submit.file.replicatio属性控制,默认是10份)以便当他们运行任务的时候有很多在集群中的父辈供NM(node manager)访问。

·通过调用在RM上的submitApplication()提交Job(步骤4)。

Job初始化

当RM收到调用它的summitApplication()方法的时候,它中断一个通向YARN调度程序的请求。这个调度程序分配一个容器,然后在NM管理下RM启动应用程序的主程序(步骤5a和5b)。

这个MR任务的主程序是一个主类是MRAppMaster的JAVA应用。它安装任务通过创建一系列的记录对象去跟踪任务的进展,它将收到从任务的过程和完成的报告(步骤6)。下一步,它在客户端内从共享文件系统中取回完成的输入切片(步骤7)。它那时会为每一个切片创建一个M(map)任务对象,同时一系列R(reduce)任务对象通过mapreduce.job.reduces属性确定(通过在Job上的setNumReduceTasks()方法设定)。任务在这时将被给个ID。

这个主程序必须决定怎样去运行组成MR的任务,可能选择和在它自己运行的JVM中运行,当它根据比较在一个节点上运行之后判断出在新容器上分配和运行任务的开销大于在本地的开销。这样的Job被叫做uberized,或者运行uber task(最好的任务)。

什么被称作一个小Job?默认来说,一个小Job是有少于10个M,只有1个R,并且输入大小少于HDFS的一个块容量(这些值可以通过mapreduce.job.ubertask.maxmaps, mapreduce.job.ubertask.maxreduces, 和 map

reduce.job.ubertask.maxbytes修改)。最好的任务这种模式必须通过设置 mapreduce.job.ubertask.enable为true被明确启用(对于单机或者整个集群)。

最后,在任何任务被开启之前,主程序在OutputCommitter上调用setupJob()方法。比如FileOutputCommiter这个默认的类,并且将为Job创建最终输出目录和为任务输出开辟的临时工作空间。这个提交协议的细节在206页的“输出提交者”。

任务分配

如果Job没有运行在最好的任务模式下,主程序就会从RM向容器请求Job内的全部的M和R任务(步骤8)。请求M任务以比R任务更高的优先级被执行,因为全部M任务必须在R任务的排序阶段之前被完成(参看197页的“洗牌和排序”)。请求R任务不被执行直到5%M任务被完成(参看308页的“R任务的慢速启动”)。

R任务能在集群的任何地方运行,但是M任务的请求有调度程序遵从的数据局部性约束(参看81页“资源请求”)。在最优的情况,任务是本地数据模式-那就是运行在和切片所在的相同的节点。另外,任务可能是本地机架模式:在相同的机架上,但不是在同一个节点的切片位置。一些任务这两种模式都不是并且从不从的机架而不是他们正在运行的地方获取数据。对于一个特别的Job,你可以通过看Job的计数器来决定运行在每个位置等级下的任务的数量(参看表9-6)。

请求也指定了完成任务需要的内存需求和CPU数量。通常来说,每个M和R任务被分配1G内存和1个虚拟核心。这个值在每个Job的基本配置是可以配置的(受301页“在YARN和MR的内存设置”中的最小值和最大值的约束),通过下面的属性:mapreduce.map.memory.mb, mapreduce.reduce.memory.mb, mapreduce.map.cpu.vcores and mapreduce.reduce.cpu.vcores。

任务执行

一旦任务被在特定节点上的容器通过RM的调度器分配资源,主程序就通过联系RM开启容器(步骤9a和9b)。任务通过主类是YarnChild的JAVA应用程序被执行。在它运行任务之前,它定位任务需要的,包括Job配置和JAR文件还有任何从分布式缓存的文件(步骤10;参看274页“分布式缓存”)这样的资源。最后,它运行M或R任务(步骤11)。

YarnChild运行在专用的JVM上以便任何用户定义的M和R的函数(甚至在YarnChild)存在的BUG不会影响到NM-比如造成它崩溃或挂起。

每个任务能执行安装和提交的操作,这些操作和这个任务自己一样运行在相同JVM并且是通过OutputCommiter被确定的(参看206页“输出提交者”)。对于基于文件的Job,提交操作从临时位置到最终位置移动任务输出。提交协议能确保冒险的操作被启用(参看204页“冒险的操作”),只有一个重复的任务被提交并且另一个被终止。

流是为了运行用户提供的可执行文件并且与之交互而运行特定的M和R任务的地方(图7-2)。

流任务用标准输入和输出流与和这个进程(它可能用任何语言被写入)交互。在执行任务期间,JAVA进程通过定义的M和R函数并且传递输出键值对回到JAVA进程来将传递输入键值对送到外部进程。从NM的观点来看就像子进程在它自身运行了M或R。


hadoop权威指南这本书 hadoop权威指南4中文版pdf_权威指南_02


图7-2流可执行文件对于NM和任务容器的关系

进程和状态更新

MRJob是长时间运行的批处理操作,从数秒到数小时的运行。因为它对于用户得到Job运行进展的反馈可能是个重要的时间长度。一个Job和每个它的任务都有一个包含Job或任务的状态(例如正在运行,成功完成,失败)、M和R的进度状态、Job的计数器和一个状态信息或描述(可能通过用户的代码设置)。这些状态改变Job的过程,然而他们怎样给客户端反馈?

当一个任务运行,它一直跟踪进展(任务完成的比例)。对于M任务,就是已经被处理过的输入比例。对于R任务,有点复杂,但是系统仍然能预测R的已经被处理的输入比例。通过将所有操作划分成3份,对应3个洗牌的阶段(参看197页“洗牌和排序”)。例如,如果任务已经运行R超过50%的进度,那么总任务进度是5/6,因为已经完成复制和排序阶段(每个1/3),并且完成了一半的R阶段(1/6)。

MR的进度是什么构成的?

进度不总是可以估测的,然而它告诉Hadoop任务正在做一些事。比如一个写入输出记录的任务正在进行,即时当它不能被表达为将要被写入的总数的百分比(因为即使任务产生输出,Hadoop可能也不知道)。

进度报告非常重要,Hadoop将不会在一个取得进展的任务上失败。下列操作构成进度:

·读取输入记录(在M或R里)

·写入输出记录(在M或R里)

·设置状态描述(通过Reporter的TaskAttemptContext的setStatus()方法)

·计数器加一(用Reporter的incrCounter()方法或者Counter的increment()方法

·调用Reporter或TaskAttempContext的progress()方法

 

任务也有一套计算当任务运行时的各种事件的计数器(我们来看个27页“一个测试运行”的例子),这计数器被编译进框架中,比如写入M的输出记录,或者用户定义的。

当M或R任务运行,子过程和它主程序通过类似脐带的接口联系。任务每3秒通过脐带接口报告它的进度和状态(包括计数器)回传给对Job有整体把握的主程序。

资源管理器的WebUI展示出全部正在运行的应用程序和可以链接到他们各自的主程序的WebUI,每个链接展示了MRJob的进一步细节,包括它的进度。

在Job的过程中,客户端通过每秒(这个区间通过mapreduce.client.progressmonitor.pollinterval被设置)通过轮询主程序收到最新状态。客户端也可以用Job的getStatus()方法获取包含全部Job状态的JobStatus实例。

在图7-3中有过程说明。


hadoop权威指南这本书 hadoop权威指南4中文版pdf_权威指南_03


图7-3 状态更新如何通过MR系统传播

Job完成

当主程序收到最后的Job任务被完成的通知,它会将Job状态改为“成功”。那时,当Job询问状态,它就会知道Job已经成功完成,所以它打印一个消息告诉用户并且返回waitForCompletion()方法。那时Job的统计和计数器会被打印到控制台上。

如果主程序被配置,那么也发送一个HTTP通知。可以通过客户端希望收到回调来配置(mapreduce.job.end-notification.url属性)。

最后,在Job完成阶段,主程序和任务容器清理他们的工作状态(所以中间输出被删除),并且OutputCommitter的commitJob()方法被调用。Job的信息通过Job历史服务被存档,如果需要的话用户可以在以后进行询问。