计算向数据移动

MR程序并不会在客户端执行任何的计算操作,它是为计算工作做好准备,例如计算出切片信息,直接影响到Map任务的并行度。

在Driver中提交任务时,会写到这样的语句:

  boolean result = job.waitForCompletion(true);

进入到waitForCompletion中:

public boolean waitForCompletion(boolean verbose) throws IOException, InterruptedException,
ClassNotFoundException {
if (state == JobState.DEFINE) {
// 提交任务语句
submit();
}
..............

继续跟进 submit():

 public void submit() throws IOException, InterruptedException, ClassNotFoundException {

    ensureState(JobState.DEFINE);
setUseNewAPI();
connect(); final JobSubmitter submitter =
getJobSubmitter(cluster.getFileSystem(), cluster.getClient());
status = ugi.doAs(new PrivilegedExceptionAction<JobStatus>() {
public JobStatus run() throws IOException, InterruptedException,
ClassNotFoundException {
// 执行提交任务
return submitter.submitJobInternal(Job.this, cluster);
}
});
..............
}

上面代码可以看出,客户端经过连接集群,获得任务提交器submitter后执行了submitJobInternal(Job.this, cluster)方法,进入看(其实我只想看切片方法)

 /**
* Internal method for submitting jobs to the system.
* The job submission process involves:
* 1、Checking the input and output specifications of the job.
* 2、Computing the InputSplits for the job.
* 3、Setup the requisite accounting information for the
* DistributedCache of the job, if necessary.
* 4、Copying the job's jar and configuration to the map-reduce system
* directory on the distributed file-system.
* 5、Submitting the job to the JobTracker and optionally
* monitoring it's status.
*/
..............
// Create the splits for the job
LOG.debug("Creating splits at " + jtFs.makeQualified(submitJobDir));
int maps = writeSplits(job, submitJobDir);
conf.setInt(MRJobConfig.NUM_MAPS, maps);
LOG.info("number of splits:" + maps);
..............

从这个方法头上的注释信息可以看到,在真正执行任务之前,客户端做了这么5件事,稍微翻译一下:

  • 检查作业的输入和输出规范;
  • 计算输入切片的数量;
  • 如有必要,为作业的DistributedCache 设置必要的记帐信息;
  • 将作业的 jar 和配置复制到分布式文件系统上的 map-reduce system 目录;
  • 将作业提交给 JobTracker 并可选择监控它的状态

可以看到执行切片的方法时writeSplits(job, submitJobDir)

private int writeSplits(org.apache.hadoop.mapreduce.JobContext job,Path jobSubmitDir) throws IOException,InterruptedException, ClassNotFoundException {
JobConf jConf = (JobConf)job.getConfiguration();
int maps;
if (jConf.getUseNewMapper()) {
maps = writeNewSplits(job, jobSubmitDir);
} else {
maps = writeOldSplits(jConf, jobSubmitDir);
}
return maps;
}

也有新旧API的区分,看新的writeNewSplits(job, jobSubmitDir)

private <T extends InputSplit>
int writeNewSplits(JobContext job, Path jobSubmitDir) throws IOException,
InterruptedException, ClassNotFoundException {
..................
// 只看切片方法
List<InputSplit> splits = input.getSplits(job);
T[] array = (T[]) splits.toArray(new InputSplit[splits.size()]);
..............
// 返回值是数组的长度,也就是切片的个数,也就是mapTask的并行度
return array.length;
}

进入切片方法,方法太长了,删除部分,留下核心业务逻辑。这个得好好说说

  public List<InputSplit> getSplits(JobContext job) throws IOException {

    // 如果没有指定的话,minSize = 1
long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));
// 如果没有指定的话,maxSize = Long.Max
long maxSize = getMaxSplitSize(job); // generate splits
List<InputSplit> splits = new ArrayList<InputSplit>();
// FileStatus这个概念来自于HDFS,存储客户端提交文件的元数据
List<FileStatus> files = listStatus(job);
for (FileStatus file: files) {
// 获取到文件的路径
Path path = file.getPath();
// 获取到文件的长度
long length = file.getLen();
if (length != 0) {
// 数据块位置数组,用于存储该文件对应的数据块的位置
BlockLocation[] blkLocations;
if (file instanceof LocatedFileStatus) {
blkLocations = ((LocatedFileStatus) file).getBlockLocations();
} else {
FileSystem fs = path.getFileSystem(job.getConfiguration());
blkLocations = fs.getFileBlockLocations(file, 0, length);
}
if (isSplitable(job, path)) { // 没有指定,默认是可分片的
long blockSize = file.getBlockSize();
// 返回默认值:切片大小 = 块大小
long splitSize = computeSplitSize(blockSize, minSize, maxSize);
// 获取整个文件的长度,用于计算切片的偏移量
long bytesRemaining = length;
// SPLIT_SLOP 的大小是1.1
// 这个判断表达式的含义是如果剩余的块体积大大于1.1倍的切片大小,继续切片
while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
// 在这计算了一步块索引
int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining); //-----------getBlockIndex() begin--------------------------------------------
protected int getBlockIndex(BlockLocation[] blkLocations, long offset) {
for (int i = 0 ; i < blkLocations.length; i++) {
// is the offset inside this block?
if ((blkLocations[i].getOffset() <= offset) &&
(offset < blkLocations[i].getOffset() + blkLocations[i].getLength())){
// 代码逻辑非常简单,就是返回当前offset是在哪个block里面
return i;
}
}
....................
//-----------getBlockIndex() end---------------------------------------------- // 计算完成之后加入切片集合
// 切片信息包括:路径,偏移量,切片大小,服务器节点【支撑计算向数据移动】
splits.add(makeSplit(path, length-bytesRemaining, splitSize,
blkLocations[blkIndex].getHosts(),
blkLocations[blkIndex].getCachedHosts()));
bytesRemaining -= splitSize;
} // 计算剩余数据块的切片信息
if (bytesRemaining != 0) {
int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
splits.add(makeSplit(path, length-bytesRemaining, bytesRemaining,
blkLocations[blkIndex].getHosts(),
blkLocations[blkIndex].getCachedHosts()));
}
} else { // not splitable :不能切片,那就是一片
splits.add(makeSplit(path, 0, length, blkLocations[0].getHosts(),
blkLocations[0].getCachedHosts()));
}
}
......
// 返回切片文件的集合。根据集合中数据的个数,就可以计算出有多少个maptask
return splits;
}

MapReduce——客户端提交任务源码分析的更多相关文章

  1. MapReduce之提交job源码分析 FileInputFormat源码解析

    MapReduce之提交job源码分析 job 提交流程源码详解 //runner 类中提交job waitForCompletion() submit(); // 1 建立连接 connect(); ...

  2. kafka C客户端librdkafka producer源码分析

    from:http://www.cnblogs.com/xhcqwl/p/3905412.html kafka C客户端librdkafka producer源码分析 简介 kafka网站上提供了C语 ...

  3. 3、MapReduce详解与源码分析

    文章目录 1 Split阶段 2 Map阶段 2.1分区 2.2排序 3 Shuffle阶段 4 Reduce阶段 1 Split阶段      首先,接到hdf文件输入,在mapreduce中的ma ...

  4. Flink命令行提交job (源码分析)

    这篇文章主要介绍从命令行到任务在Driver端运行的过程 通过flink run 命令提交jar包运行程序 以yarn 模式提交任务命令类似于: flink run -m yarn-cluster X ...

  5. solr源码分析之solrclound

    一.简介 SolrCloud是Solr4.0版本以后基于Solr和Zookeeper的分布式搜索方案.SolrCloud是Solr的基于Zookeeper一种部署方式.Solr可以以多种方式部署,例如 ...

  6. MapReduce源码分析之新API作业提交(二):连接集群

    MapReduce作业提交时连接集群是通过Job的connect()方法实现的,它实际上是构造集群Cluster实例cluster,代码如下: private synchronized void co ...

  7. MapReduce源码分析之JobSubmitter(一)

    JobSubmitter,顾名思义,它是MapReduce中作业提交者,而实际上JobSubmitter除了构造方法外,对外提供的唯一一个非private成员变量或方法就是submitJobInter ...

  8. MapReduce 切片机制源码分析

    总体来说大概有以下2个大的步骤 1.连接集群(yarnrunner或者是localjobrunner) 2.submitter.submitJobInternal()在该方法中会创建提交路径,计算切片 ...

  9. RocketMQ源码分析之RocketMQ事务消息实现原理上篇(二阶段提交)

    在阅读本文前,若您对RocketMQ技术感兴趣,请加入 RocketMQ技术交流群 根据上文的描述,发送事务消息的入口为: TransactionMQProducer#sendMessageInTra ...

随机推荐

  1. 病毒木马查杀实战第014篇:U盘病毒之手动查杀

    在U盘中发现病毒 前段时间需要往虚拟机中拷贝点资料,如同往常一样,插上我的U盘,并且在虚拟机的设置中选择连接U盘.奇怪的是这次的连接时间较以往长,并且还出现了"自动播放"窗口: 图 ...

  2. hdu3018 一笔画问题

    题意:       给你一幅画,这幅画由点和边构成,问你最少几笔能把这幅画画完. 思路:      这个题目的结论比较巧妙,首先我们考虑下,如果给的图是欧拉图,或者是条欧拉回路,那么我们一笔就搞定了, ...

  3. POJ3277 线段树段更新,点询问+二分离散化+暴力

    题意:       x轴上有一些矩形,问你这些矩形覆盖的面积和是多少. 思路:       首先范围很大,n很小,果断离散化,然后我们就是求出任意区间的最大值作为当前区间的高,最后在算一遍答案就行了, ...

  4. apk 脱壳

    在理解android的类加载后,我们可以愉快对apk来脱壳了.脱壳重要的是断点: 断点:在哪个位置脱壳,这里着重指的是在哪个方法 先介绍断点,我们只要知道加壳是用哪个方法来加载dex的,hook这个方 ...

  5. 3.逆向分析Hello World!程序-下

    5.继续补充,常用操作指令: Ctrl+G    Go to       移动到指定地址,用来查看代码或内存,运行时不可用 F4        Execute till Cursor 执行到光标位置, ...

  6. ppt技巧--线条

    声明:本文所有截图来源于网易云课堂--<和秋叶一起学PPT>,只做个人复习之用,特此声明! 线条的五种用途:

  7. C#可空类型及其衍生运算符

    这节讲一下C#可空类型(Nullable) 我们知道,值类型在使用前必须设置值,而引用类型则可以是null,但在某些情况下,为值类型设置为空是必要的(如处理数据库数据的时候),微软因此推出了可空类型  ...

  8. 看完这篇包你进大厂,实战即时聊天,一文说明白:聊天服务器+聊天客户端+Web管理控制台。

    一.前言 说实话,写这个玩意儿是我上周刚刚产生的想法,本想写完后把代码挂上来赚点积分也不错.写完后发现这东西值得写一篇文章,授人予鱼不如授人以渔嘛(这句话是这么说的吧),顺便赚点应届学生MM的膜拜那就 ...

  9. Codeforces Round #713 (Div. 3)AB题

    Codeforces Round #713 (Div. 3) Editorial 记录一下自己写的前二题本人比较菜 A. Spy Detected! You are given an array a ...

  10. C++ primer plus读书笔记——第13章 类继承

    第13章 类继承 1. 如果购买厂商的C库,除非厂商提供库函数的源代码,否则您将无法根据自己的需求,对函数进行扩展或修改.但如果是类库,只要其提供了类方法的头文件和编译后的代码,仍可以使用库中的类派生 ...