计算向数据移动

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. hdu4720 三角形的外接圆

    题意:       给你四个点,问你第四个点是否在前三个点围成的三角形的外接圆上. 思路:       水题,就是练练用魔板罢了,当该三角形是锐角三角形的时候,圆心是任意两条边中垂线的交点,半径是圆心 ...

  2. Java中的结构语句

    目录 循环语句 While循环 do...While循环 for循环 增强型for语句 条件语句 if..else语句 if...else if...else 语句 嵌套的 if-else 语句 sw ...

  3. SQL必学必会笔记 —— 基础篇

    基础篇 SQL语言按照功能划分 DDL(DataDefinitionLanguage),也就是数据定义语言,它用来定义我们的数据库对象,包括 数据库.数据表和列.通过使用DDL,可以创建,删除和修改数 ...

  4. 6.注册CRT 以及SecureCRT访问

    1.什么是 SecureCRT SecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,简单地说是Windows下登录Unix或Linux服务器主 机的软件. 1)准备工作:安装好Se ...

  5. Java 正则表达式实例操作

    Regular Expression正则表达式,简称RegExp,常规通用的表达式,在多个开发语言中都有它的实现,可以通过正则表达式来快速的检索.匹配.查找.替换字符串中的文本. 简单实例 匹配网址 ...

  6. ThreadLocal内存溢出代码演示和原因分析!

    ThreadLocal 翻译成中文是线程本地变量的意思,也就是说它是线程中的私有变量,每个线程只能操作自己的私有变量,所以不会造成线程不安全的问题. ​ 线程不安全是指,多个线程在同一时刻对同一个全局 ...

  7. rsync同步遇到的报错和解决办法

    rsync同步遇到的报错和解决办法   科技小能手 2017-11-12 18:27:00 浏览1125 配置 code 同步 open stream file read   在同步的客户端操作: [ ...

  8. s9 Linux 进程管理命令

    9.1 ps:查看进程 9.2-3 pstree & pgrep 9.4-6 kill & killall & pkill 9.7 top:实时显示系统中各个进程的资源占用状况 ...

  9. 快成物流科技 x mPaaS | 小程序容器加持下的技术架构“提质增效”

      导言 从 2017 年开始,GMTC"移动技术大会"就更名为"大前端技术大会".发展至今,混合开发.原生开发.前端开发等概念正在深度融合,组成"大 ...

  10. CoSky 高性能 服务注册/发现 & 配置中心

    CoSky 基于 Redis 的服务治理平台(服务注册/发现 & 配置中心) Consul + Sky = CoSky CoSky 是一个轻量级.低成本的服务注册.服务发现. 配置服务 SDK ...