MapReduce 的过程详解

来源:互联网 发布:淘宝店铺如何加权重 编辑:程序博客网 时间:2024/05/18 00:45

mapreduce 过程如下图所示:



从整体上,mapreduce 框架可以分为五个不同实体:

1)客户端:提交 MapReduce job。

2)Yarn 资源管理器(resource manager):协调集群计算资源的分配

3)Yarn 节点管理器(node manager):启动和监视集群中每个节点的计算容器。

4)Mapreduce 应用管理器(application master):负责调度 mapreduce 任务。应用管理器和 MapReduce 任务是运行在容器中的,这个容器是由资源管理器分配的,并且接受阶段管理器的管理。

5) 分布式文件系统(通常为HDFS):用与上述不同实体之间文件的共享。


下面详细讲述mapreduce各个阶段的详细过程:

1 提交job

调用Job 对像的 submit() 方法将会创建一个JobSubmitter 实例,并且调用它的submitJobInternal()方法,进行job的提交。提交 job 以后, waitForCompletion()方法将每隔一秒钟 poll job 的运行状态,如果job的运行状态发生了改变则显示到控制台上。当job成功执行完毕,则会输出job 的统计细心,否则输出job出错的信息。

job 提交过程:

1)向 yarn 资源管理器申请一个新的 应用id(applicaiton id),用于唯一标示这个 mapreduce job。

2)检查job的输出路径是否合法。如果输出文件已经存在,则job不会提交,而是抛出异常,终止程序运行。

3)计算job的输入分片(input splits)。如果分片计算失败(比如输入文件不存在),则job不会被提交,抛出异常,程序终止。

4)将运行 job 需要的文件(job 的jar 包,配置文件和计算的输入分片)上传到共享文件系统(hdfs)的一个文件夹中(以这个job的 job ID 命名)。

5)调用资源管理器的 submitApplication() 方法,开始执行job。


2 job 初始化

当资源管理的submitApplication方法被调用时,资源管理器将请求转发给 Yarn 调度器。yarn 调度器分配出一个容器,资源管理器便在这个容器上启动应用管理器进程,容器的运行受节点管理器管理。

mapreduce 的应用管理器时一个java 程序,它的 main class 时 MRAppMaster。job初始化:它将会产生一些 bookkeeping 对像去跟踪job的运行状态,这些 bookkeeping对向接受task传来的运行报告。然后MRAppmaster 从 hdfs 上得到客户端计算的job的输入分片。MR 在每个输入分片上创建一个 map task,和一些 reduce task(由 mapreduce。job。reduces 属性决定或者 job对向的 setNumReduceTasks() 方法)。每个task都给一个ID。

应用管理器必须根据mapreduce去决定如何执行task。如果job很小,那么MR也许会选择在同一个jvm中完成它。这是因为申请容器和启动容器都是由花销的,并行计算带来的收益和花销相互抵消,反而不如在一个节点上执行的效率高

3 task 的分配

如果task在本地节点运行并不能带来好处,那么MR将会向资源管理器申请运行job的map 和 reduce 任务的容器。map 任务容器申请的优先级是高于reduce容器的,因为reduce必须等到map阶段全部都完成了才可以真正执行(除了reduce的准备阶段)。当map任务完成了5%,才开始申请reduce阶段需要的容器。

下面讲讲map 和 reduce 阶段容器的分配问题。运行reduce 任务的容器可以在节点上的任意节点,但是map容器的分配则要遵循一定条件。首先,尽可能在输入分片所在节点上分配容器,如果分配不了,则在和分片在同一个机架上的节点上分配容器,如果还是没有资源分配容器的话,那只好在任意机架上分配容器了,此时数据要跨越机架传递,效率不高。

容器申请请求还会指定运行task所需的内存和CPU资源。默认情况下,每个map和reduce任务分配1024M内存和一个虚拟核。每个job可以根据自身情况自由设置:mapreduce.map.memory.mb  、 mapreduce.reduce.memory.mb 、 mapreduce.map.cpu.vcores 、 mapreduce.reduce.cpu.vcores


4 任务执行

一旦一个task获得了资源管理器在指定节点上分配给它所需的内存和cpu资源,应用管理器则联系那个节点的节点管理器,然后启动该容器。任务是一个java应用,它的main class 是 YarnChild。在开始运行之前,它会从共享文件系统中获取它需要的资源,包括job配置文件、jar包,其他相关文件。获取了这些资源以后,便开始运行map或者reduce任务。

YarnChild 是运行在一个独立的jvm中,因此,用户定义的map和reduce函数在运行过程中产生的任何bug都不会影响到节点管理器的状态,比如导致节点管理器进程崩溃或者挂起。


5 运行过程和状态更新

mapreduce job往往都是比较耗时的,需要长时间运行的批处理程序,花费的时间从数十秒到数十小时,所以用户需要知道job运行在运行时候的状态。job和task都有状态:比如running、successfully、completed、failed。这小消息在job运行过程中不断发生变化,那么客户端如何知道这些呢?

当一个task在运行的时候,它会跟踪task运行的过程(task完成的比例)。比如map task,任务完成的比例是已被处理的输入数据的比例。对于reduce task则要复杂一点。它将reduce阶段分为三个部分,和shuffle三个阶段向对应。比如:reduce 阶段如果正在运行reduce函数,那么任务已经被完成5/6。

6 job 成功完成

当应用管理器收到通知:job的最后一个task已经完成了,那么它把job的状态改为 “successful”。然后在控制台输出job的统计信息。应用管理器和task容器清理工作环境。此时job的信息便可以在job 历史服务器里可以查询了。

7 job 失败

在真实环境中,job失败是很常见的。通常失败包括 1 task 失败 2 应用管理器失败  3 节点管理器失败  4 资源管理器失败。下面分别叙。

1)task 失败

当用户自定义的map 或者reduce task在运行过程中抛出异常,task jvm 会将异常上报到 应用管理器然后在退出。异常信息会被记入用户的日志。应用管理器将这个task标记为失败,并释放这个task占据的资源。

还有一种情况是task jvm 由于某种原因(也许是jvm自身bug导致的)突然终止了,但是没有来得及向应用管理器汇报,此时节点管理器会注意到,并将此异常上报到 应用管理器,应用管理器将这个task标记为失败。

还有一种情况,task进程被挂起了。如果应用管理器在一段时间内没有更新task的状态,则会被认为已经失败了。task 容器会自动被杀死。mapreduce.task.timeout 参数设置超时时间,默认是10分钟。

如果将超时时间设置为0,则不开启超时功能,这个适合于7*24小时的应用。

当一个task尝试运行失败,那么应用管理器会在另外一个节点上再次尝试执行。默认情况下,它最多尝试四次。这个次数是可以配置的。默认情况下,任何一个task失败了四次,则整个job被认为是失败的。

但是也可以设置失败的task比例不超过一定比例,则job依然可以继续执行。

一个task也可以被杀死,这个和失败是不一样的。

2)应用管理器失败

Mapreduce 的应用管理器失败了会再次尝试运行,默认会尝试运行两次。如果两次都失败则job运行失败。mapreduce.am.max-attempts 设置最多尝试次数。但是yarn资源管理器限制应用管理器最大的失败重启次数,每个应用都不能超过这个限制。yarn.resourcemanager.am.max-attempts ,默认是两次。

应用管理器失败重启机制:AM 会周期性向资源管理器发送心跳,如果资源管理器发现 AM 已经挂掉了,那么它会在一个新的容器中开启另一个AM实例。此时新的AM实例会利用job的历史服务器去恢复正在运行的 task 的状态,所以正在进行和已经完成的task不需要再次运行。如果不想让job继续执行,则可以关闭这个功能,让job重新执行:将 yarn.app.mapreduce.am.job.recovery.enable 设置为 false。

Mapreduce 客户端会向应用管理器询问job运行的状态。在job初始化时,MR 客户端会向资源管理器询问AM 的地址,客户端将这个信息缓存起来。如果AM 失败了,那么客户端请求将会超时,此时客户端会再次询问资源管理器 AM 的地址。

3) 节点管理器失败

如果一个节点管理器进程崩溃了,那么资源管理器将不会收到这个节点的心跳消息。默认情况下,如果资源管理器超过10分钟(yarn.resourcemanager.nm.liveness-monitor.expiry-interval-ms)没有收到节点管理器的心跳消息,则认为它已经挂了,然后将它从自己的列表中删除。

任何在这个失败的节点管理器上运行的task会恢复运行。

4)资源管理器失败

资源管理器的失败时很严重的。默认配置下,资源管理器存在单点故障,一旦失败,则所有job都不被恢复。

为了高可用,可以同时运行两个资源管理器,另一作为备用。如果活动的资源管理失败了,那么启用备用资源管理器,此时客户段不会收到严重影响。

客户端和节点管理器也要被配置成可以处理资源管理器失败的情况。因为此时可能有两个资源管理器。它们会尝试联系每一个资源管理直到发现活动的资源管理。如果活动的资源管理器失败了,那么它们会再次遍历连接的资源管理器,直到备用的资源管理变为活动状态。

8 mapreduce 的shuffle 和sort

mapreduce框架会保证每个reducer的输入数据都是按照key排好序的。从map的输出结果到这排序阶段就被成为ishuffle阶段,这个阶段时mapreduce阶段的精华也是难点,这部分的代码在每个版本中改动最多。

shuffle:将map输出结果送到reducer和排序的功能。

1) map:每个map task将结果输出到环形内存缓冲区,当到达一定阈值,则启动一个后台进程将缓存中的数据 1: 按照 reduce 阶段 reducer 的个数将数据分区,然后在每个分区里面的数据按照key键值排序,下一步,如果设置了 combiner 函数,则将这个combiner函数作用于上一步的结果,然后就是把数据保存到磁盘。
注意:
当这个后台进程将内存中的数据写入磁盘的时候,如果缓存已经满了,那么task会阻塞,直到spill阶段完成。
内存缓存默认是 100M,每当到达阈值则生成一个spill文件,task完成了以后,将多个spill文件合并成一个文件。这个文件是分区的,而且每个分区中的数据都是按key值排好序的。
可以让数据压缩
map 的数据是通过 http 传输给 reducer 的。
2)reduce:reducer 要执行任务,则第一步就需要获得 map 阶段输出到磁盘的数据。这个阶段叫做 copy phase。每个 reducer 默认有5个用于从远程机器获取数据的线程,并行执行。
  map task 完成以后会利用心跳机制通知 application master 。application master 知道 map 和 host 的对应关系。 每个reducer 有一个线程会周期性的询问 master map 阶段的输出数据位置,直到它已经获得所有map 阶段的数据为止。
copy phase:
1 如果 map 输出结果数据量比较小,则直接放在内存中,否则放到磁盘中。
2 当内存中的数据到达一定阈值,则将数据合并然后spill 到磁盘。(如果配置了 combiner , 那么保存到磁盘之前进行 combine)
3 copy 阶段继续执行,会开启一个后台进程将多个小文件合并并排序生成一个大文件。
4 当 map task 有一个完成了则开始 copy phase 
sorted phase:
当map阶段文件都已经copy到reducer段然后执行 sorted phase(merge phase)。
1 将各个 map 输出的文件合并。
reduce phase:
将 sorted 阶段的结果作为 reduce 函数的输入,输出结果,如果是hdfs文件,那么第一个block将保存在本地节点的机器上。
9 调优
调优的一般原则是:shuffle阶段的内存越大越好。
1)map reduce 函数占用的内存越少越好,尽量少用 Map 做聚合统计。
2)map 和 reduce task 占用的内存:mapred.child.java.opts,尽可能设置大点。
3)map 阶段的spill文件次数尽可能少


1 0
原创粉丝点击