MapReduce 程序的核心运行机制

1、概述

一个完整的 MapReduce 程序在分布式运行时有两类实例进程:
1、MRAppMaster:负责整个程序的过程调度及状态协调;
2、Yarnchild:负责 map 阶段的整个数据处理流程;
3、Yarnchild:负责 reduce 阶段的整个数据处理流程。
以上两个阶段 MapTask 和 ReduceTask 的进程都是 YarnChild,并不是说这 MapTask 和 ReduceTask 就跑在同一个 YarnChild 进行里。

2、MapReduce 程序的运行流程

1、一个 mr 程序启动的时候,最先启动的是 MRAppMaster,MRAppMaster 启动后根据本次 job 的描述信息,计算出需要的 maptask 实例数量,然后向集群申请机器启动相应数量的
maptask 进程。
2、 maptask 进程启动之后,根据给定的数据切片(哪个文件的哪个偏移量范围)范围进行数据处理,主体流程为:
A、利用客户指定的 InputFormat 来获取 RecordReader 读取数据,形成输入 KV 对 。
B、将输入 KV 对传递给客户定义的 map()方法,做逻辑运算,并将 map()方法输出的 KV 对收集到缓存。
C、将缓存中的 KV 对按照 K 分区排序后不断溢写到磁盘文件。
3、 MRAppMaster 监控到所有 maptask 进程任务完成之后(真实情况是,某些 maptask 进程处理完成后,就会开始启动 reducetask 去已完成的 maptask 处 fetch 数据),会根据客户指定的参数启动相应数量的 reducetask 进程,并告知 reducetask 进程要处理的数据范围(数据分区)。
4、Reducetask 进程启动之后,根据 MRAppMaster 告知的待处理数据所在位置,从若干台 maptask 运行所在机器上获取到若干个 maptask 输出结果文件,并在本地进行重新归并排序,
然后按照相同 key 的 KV 为一个组,调用客户定义的 reduce()方法进行逻辑运算,并收集运算输出的结果 KV,然后调用客户指定的 OutputFormat 将结果数据输出到外部存储。

3、MapTask 并行度决定机制

1、maptask 的并行度决定 map 阶段的任务处理并发度,进而影响到整个 job 的处理速度。
2、那么,mapTask 并行实例是否越多越好呢?其并行度又是如何决定呢?
一个 job 的 map 阶段并行度由客户端在提交 job 时决定,客户端对 map 阶段并行度的规划的基本逻辑为:
将待处理数据执行逻辑切片(即按照一个特定切片大小,将待处理数据划分成逻辑上的多个 split),然后每一个 split 分配一个 mapTask 并行实例处理。
3、这段逻辑及形成的切片规划描述文件,是由FileInputFormat实现类的getSplits()方法完成的。该方法返回的是 List,InputSplit 封装了每一个逻辑切片的信息,包括长度和位置信息,而 getSplits()方法返回一组 InputSplit。

4、切片机制

切片 spilt:
逻辑上的概念,只是一个范围的划分;
针对计算任务(maptask),为计算任务准备数据;
不会进行真正的物理上的切分数据。
面试题:切片 split 与块 block 的区别联系?
1、FileInputFormat 中默认的切片机制:
(1)简单地按照文件的内容长度进行切片;
(2)切片大小,默认等于 block 大小;
(3)切片时不考虑数据集整体,而是逐个针对每一个文件单独切片;
比如待处理数据有两个文件:
File1.txt 200M
File2.txt 100M
经过 **getSplits()**方法处理之后(方法参数:JobContext job,上下文对象;方法返回值:List,InputSplit 输入切片,每一个切片封装成一个 InputSplit),形成的切片信息是:
File1.txt-split1 0-128M
File1.txt-split2 129M-200M
File2.txt-split1 0-100M
2、FileInputFormat 中切片的大小的参数配置:
(1)通过分析源码,在 FileInputFormat 中,计算切片大小的逻辑(底层源码):
long splitSize = computeSplitSize(blockSize, minSize, maxSize),翻译一下就是求这三个值的中间值。
(2)切片主要由这几个值来运算决定:
blocksize:默认是 128M,可通过 dfs.blocksize 修改;
minSize:默认是 1,可通过 mapreduce.input.fileinputformat.split.minsize 修改;
maxsize:默认是 Long.MaxValue,可通过 mapreduce.input.fileinputformat.split.maxsize 修改;
3、修改切片大小:
(1)如果 maxsize 调的比 blocksize 小,则切片会小于 blocksize;如果 minsize 调的比 blocksize 大,则切片会大于 blocksize;
(2)代码中修改:在 Driver 端设定切片大小,只针对当前 mapreduce 的任务:
FileInputFormat.setMinInputSplitSize(job, size);
FileInputFormat.setMaxInputSplitSize(job, size);

但是,不论怎么调参数,都不能让多个小文件“划入”一个 split
(1)每一个文件的大小小于 block 切块,这个文件单独成一个 split 切片,启动一个 maptask 任务;
(2)每一个 maptask 任务运行的时候,对应一个 JVM 进程,Yarnchild;
(3)每一个 maptask 任务,是 map 端执行分布式计算的最小单位了,一个 maptask 任务只能在一个节点上运行;
(4)最后一个切片大小问题:
(double)bytesRemaining / splitSize(切片大小) > SPLIT_SLOP 1.1
剩余的大小 > 切片的1.1倍的时候,才会进行切分。
一个文件的最后一个切分的大小,最大达到 1.1 * 128 = 140.8M
最后一个切片,跨节点的问题:
这个时候最后一个切片跨节点传输性能比再开一个 maptask 任务划算的。
一个文件大小 ==》 260M
存储: 3个数据块
blk0 0-128M
blk1 128-256M
blk2 256-260M

计算的时候,先划分逻辑切片:
split0 0-128M
逻辑切分完第一个之后剩余 132M ,不符合切分条件;
split1 128-260M blk1 blk2

5、MapTask 并行度经验之谈

如果硬件配置为 2*12core + 64G,恰当的 map 并行度是大约每个节点 20-100 个 map,最好每个 map 的执行时间至少一分钟。
1、如果 job 的每个 map 或者 reduce task 的运行时间都只有 30-40 秒钟,那么就减少该 job 的 map 或者 reduce 数,每一个 task(map|reduce)的 setup 和加入到调度器中进行调度,这个中间的过程可能都要花费几秒钟,所以如果每个 task 都非常快就跑完了,就会在 task 的开始和结束的时候浪费太多的时间。
配置 task 的 JVM 重用可以改善该问题:
mapred.job.reuse.jvm.num.tasks,默认是 1,表示一个 JVM 上最多可以顺序执行的 task 数目(属于同一个 Job)是 1。也就是说一个 task 启一个 JVM。这个值可以在 mapred-site.xml
中进行更改,当设置成多个,就意味着这多个 task 运行在同一个 JVM 上,但不是同时执行,是排队顺序执行。
2、如果 input 的文件非常的大,比如 1TB,可以考虑将 hdfs 上的每个 blocksize 设大,比如设成 256MB 或者 512MB。

3、总结:
(1)maptask:运行 map 端逻辑的任务,
(2)maptask的并行度:map 端任务的个数,map端的分布式;当数据量很大的时候,map 端的任务,切分成多个小任务执行。
(3)如何分配每一个 maptask?每一个 maptask 任务需要对应多少数据量?
假设 HDFS 上有一个 300M 的文件存储:
blk0 0-128M
blk1 128-256M
blk2 256-300M
假设一个 maptask 任务对应 300M 启动一个maptask任务,任务面向的是3个块,3个块都有可能跨节点存储。这个maptask任务需要跨节点传输数据(网络+磁盘IO),不合理。
假设一个 maptask 任务对应 100M,启动3个 maptask:
maptask0 ===> 0-100M ===> blk0 1-100M
maptask1 ===> 100-200M ===> blk0 100-128M,blk1 128-200M
maptask2 ===> 200-300M ===> blk1 200-256M,blk2 256-300M
最合理的是一个 maptask 任务 ====> 一个 block 块;
事实上一个 maptask 任务对应的一个切片 split 大小
推测:一个 split 切片大小 ====> 一个块 block 大小;

6、ReduceTask 并行度决定机制

1、reducetask 的并行度同样影响整个 job 的执行并发度和执行效率,但与 maptask 的并发数由切片数决定不同,Reducetask 数量的决定是可以直接手动设置:
job.setNumReduceTasks(4);
默认值是 1,手动设置为 4,表示运行 4 个 reduceTask,设置为 0,表示不运行 reduceTask 任务,也就是没有 reducer 阶段,只有 mapper 阶段。
2、如果数据分布不均匀,就有可能在 reduce 阶段产生数据倾斜。
注意:reducetask 数量并不是任意设置,还要考虑业务逻辑需求,有些情况下,需要计算全局汇总结果,就只能有 1 个 reducetask ,尽量不要运行太多的 reducetask。对大多数 job 来说,最好 rduce 的个数最多和集群中的 reduce 持平,或者比集群的 reduce slots 小。这个对于小集群而言,尤其重要。

7、学习内容

上节学习内容:MapReduce 基础入门了解
下节学习内容:MapReduce 编程作业

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值