计算向数据移动

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. 手动脱PeCompact 2.20壳实战

    作者:Fly2015 PeCompact壳又是一个没有听说过的壳,需要脱壳的程序是吾爱破解培训的第一课的选修作业四.最近对脱壳有点上瘾了,当然也遭受了脱壳受挫的无奈,但是比较幸运还是把这个壳给搞了. ...

  2. 使用EasySYS搭建驱动开发基本框架

    提供EasySYS的下载地址:http://bbs.pediy.com/showthread.php?p=956643,看雪上有提供下载,自行百度. EasySYS你能够帮我们快速的搭建驱动的开发框架 ...

  3. DexHunter在ART虚拟机模式下的脱壳原理分析

    本文博客地址: http://blog.csdn.net/qq1084283172/article/details/78494620 DexHunter脱壳工具在Dalvik虚拟机模式下的脱壳原理分析 ...

  4. LA3027简单带权并查集

    题意:       有n个点,一开始大家都是独立的点,然后给出一些关系,a,b表示a是b的父亲节点,距离是abs(a-b)%1000,然后有一些询问,每次询问一个节点a到父亲节点的距离是多少? 思路: ...

  5. 7.PHP Cookie与Session

    Cookie与Session Cookie Cookie功能 创建cookie <?PHP    setcookie("TMCookie" ,'www.baidu.com') ...

  6. Windows PE资源表编程(枚举资源树)

    资源枚举 写一个例子,枚举一个PE文件的资源表.首先说下资源相关的作为铺垫. 1.资源类型也是PE可选头中数据目录的一种.位于第三个类型. 2.资源目录分为三层.第四层是描述文件相关的.这些结构是按照 ...

  7. 面试侃集合 | ArrayBlockingQueue篇

    面试官:平常在工作中你都用过什么什么集合? Hydra:用过 ArrayList.HashMap,呃-没有了 面试官:好的,回家等通知吧- 不知道大家在面试中是否也有过这样的经历,工作中仅仅用过的那么 ...

  8. 带你解析MySQL binlog

    前言: 我们都知道,binlog可以说是MySQL中比较重要的日志了,在日常学习及运维过程中,也经常会遇到.不清楚你对binlog了解多少呢?本篇文章将从binlog作用.binlog相关参数.解析b ...

  9. [bug] org.apache.spark.sql.AnalysisException: Table or view not found spark

    参考 https://blog.csdn.net/weixin_44634893/article/details/89629399

  10. [Java] Structs

    背景 基于MVC的WEB框架 在表示层过滤访问请求并处理 步骤 在eclipse中创建Web动态项目 导入相关jar包到WEB-INF/lib 在WEB-INF目录下新建web.xml,配置Filte ...