本节内容完全来自
深入理解大数据:大数据处理与编程实践 机械工业出版社
没啥好说的,直接上内容
一、作业
- 首先, 用户程序客户端通过作业客户端接口程序JobClient提交一个用户程序。
- 然后JobClient向JobTracker提交作业执行请求并获得一个Job ID。
- JobClient同时也会将用户程序作业和待处理的数据文件信息准备好并存储在HDFS中。
- JobClient正式向JobTracker提交和执行该作业。
- JobTracker接受并调度该作业,并进行作业的初始化准备工作, 根据待处理数据的实际的分片情况, 调度和分配一定的Map节点来完成作业。
- JobTracker查询作业中的数据分片信息, 构建并准备相应的任务。
- JobTracker启动TaskTracker节点开始执行具体的任务。
- TaskTracker根据所分配的具体任务, 获取相应的作业数据。
- TaskTracker节点创建所需要的Java虚拟机, 并启动相应的Map任务(或Reduce任务)的执行。
- TaskTracker执行完所分配的任务之后, 若是Map任务, 则把中间结果数据输出到HDFS中;若是 Reduce任务,则输出最终结果
- TaskTracker向JobTracker报告所分配的任务完成。 若是Map任务完成并且后续还有 Reduce任务 则JobTracker会分配和启动 Reduce节点继续处理中间结果并输出最终结果。
二、包含任务的细粒度作业流程
作业执行流程
作业提交后成,总体上可以把作业的运行和生命周期分为三个阶段: 准备阶段(PREP)、 运行阶段(RUNNING)和结束阶段(FINISHED)。
在准备阶段, 作业从初始状态NEW开始, 进入PREP.INITIALIZING状态进行初始化 初始化所做的主要工作是读取输入数据块描述信息, 并创建所有的Map任务和Reduce任务。初始化成功 后,进入PREP.INITIALIZED状态。此后,一个特殊的作业初始化任务(job setup task) 被启动,以创建作业运行环境,此任务完成后,作业准备阶段结束 作业真正进入了运行阶段 。
在运行阶段作业首先处在 RUNNING.RUN_WAIT状态下等待任务被调度。 当第一个任务开始执行时,作业进入RUNNING.RUNNING_TASKS, 以进行 真正的计算。 当所有的Map任务和Reduce任务执行完成后, 作业进入RUNNING.SUC_WAIT状态。此时, 另一个特殊的作业清理任务(job cleanup task)被启动, 清理作业的运行环境, 作业进入结束阶段 。在结束阶段, 作业清理任务完成后, 作业最终到达成功状态SUCCEEDED, 至此, 整个 作业的 生命周期结束 。在整个过程中,各个状态下作业有可能被客户主动杀死, 最终进入KILLED状态;也有可,能在执行中因各种因素而失败, 最终进入FAILED状态。
任务执行流程
任务(Task)是HadoopMapReduce框架进行并行化计算的基本单位。 需要说明的一点是:任务是一个逻辑上的概念, 在MapReduce并行计算框架的实现中布千JobTracker和TaskTracker两端, 分别对应TasklnProgress和TaskTracker.TasklnProgress两个对象。当一个作业提交到 Hadoop系统时,JobTracker对作业进行初始化, 作业内的任务(TasklnProgress)被全部创建好,等待 TaskTracker来请求任务, 我们对任务 的分析就从这里开始 。
- JobTracker为作业创建一个新 的TasklnProgress任务 ;此时Task处在 UNASSIGNED状态。
- TaskTracker 经过一个心跳周期 后, 向JobTracker发送一次心跳消息(heartbeat), 请求分配任务, JobTracker收到请求 后分配个 TasklnProgress任务 给TaskTracker 。 这是第一次心跳通信, 心跳间隔一般为3秒。
- TaskTracker收到任务 后, 创建 一个对应的 TaskTracker. TasklnProgress对象, 并启动独立的Child 进程去执行这个任务 。此时 TaskTracker已将任务状态更新为 RUNNING 。
- 又经过一个心跳周期, TaskTracker向JobTracker报告任务状态的改变, JobTracker也将任务状态更新为 RUNNIN1G 。 这是第二次心跳通信 。
- 经过一定时间,任务在Child进程内执行完成,Child进程向TaskTracker进程发出通知, 任务状态变为 COMMIT_PENDING (任务在执行期间 TaskTracker 还会周期性地向JobTracker 发送心跳信息 )。
- TaskTracker 再次向 JobTracker 发送心跳信息报告任务状态的改变, JobTracker 收到消息后也将任务状态更新为 COMMIT—PENDING, 并返回确认消息, 允许提交。
- TaskTracker 收到确认可以提交的消息后将结果提交, 并把任务状态更新为SUCCEEDED。
- 一个心跳周期后 TaskTracker 再次发送心跳消息, JobTracker 收到消息后也更新任务的状态为 SUCCEEDED, 一个任务至此结束。
抛个问题,有了上面的知识之后,那么MapReduce是如何确定Map和Reduce的数量呢?
首先,还记得前面介绍Map的时候,谈到了分片(Split),我们说一个分片就对应一个Map任务。所以一般来讲,Map task的数量应该是和Split息息相关的。
以下内容来自
[1] 如何确定 Hadoop map和reduce的个数–map和reduce数量之间的关系是什么? https://blog.csdn.net/u013063153/article/details/73823963
Map数量
map的数量通常是由hadoop集群的DFS块大小确定的,也就是输入文件的总块数,正常的map数量的并行规模大致是每一个Node是10~100个,对于CPU消耗较小的作业可以设置Map数量为300个左右,但是由于hadoop的每一个任务在初始化时需要一定的时间,因此比较合理的情况是每个map执行的时间至少超过1分钟。具体的数据分片是这样的,InputFormat在默认情况下会根据hadoop集群的DFS块大小进行分片,每一个分片会由一个map任务来进行处理,当然用户还是可以通过参数mapred.min.split.size参数在作业提交客户端进行自定义设置。还有一个重要参数就是mapred.map.tasks,这个参数设置的map数量仅仅是一个提示,只有当InputFormat 决定了map任务的个数比mapred.map.tasks值小时才起作用。同样,Map任务的个数也能通过使用JobConf 的conf.setNumMapTasks(int num)方法来手动地设置。这个方法能够用来增加map任务的个数,但是不能设定任务的个数小于Hadoop系统通过分割输入数据得到的值。当然为了提高集群的并发效率,可以设置一个默认的map数量,当用户的map数量较小或者比本身自动分割的值还小时可以使用一个相对交大的默认值,从而提高整体hadoop集群的效率。
reduce数量
reduce在运行时往往需要从相关map端复制数据到reduce节点来处理,因此相比于map任务。reduce节点资源是相对比较缺少的,同时相对运行较慢,正确的reduce任务的个数应该是0.95或者1.75 *(节点数 ×mapred.tasktracker.tasks.maximum参数值)。如果任务数是节点个数的0.95倍,那么所有的reduce任务能够在 map任务的输出传输结束后同时开始运行。如果任务数是节点个数的1.75倍,那么高速的节点会在完成他们第一批reduce任务计算之后开始计算第二批 reduce任务,这样的情况更有利于负载均衡。同时需要注意增加reduce的数量虽然会增加系统的资源开销,但是可以改善负载匀衡,降低任务失败带来的负面影响。同样,Reduce任务也能够与 map任务一样,通过设定JobConf 的conf.setNumReduceTasks(int num)方法来增加任务个数。有些作业不需要进行归约进行处理,那么就可以设置reduce的数量为0来进行处理,这种情况下用户的作业运行速度相对较高,map的输出会直接写入到 SetOutputPath(path)设置的输出目录,而不是作为中间结果写到本地。同时Hadoop框架在写入文件系统前并不对之进行排序。