Driver的提交:
在此以简单的WordCount为例,通过DEBUG来了解Driver中submit()方法的执行流程(案例不是关键,重在通过源码学习submit的设计原理)
1.前期准备:WordCount部分,在本地或虚拟机hadoop目录下创建一个简单的txt文本文件即可(我在本地d盘创建),内容随意如
hadoop hadoop
spark
hadoop atguigu
spark
hello WordCount
接下来各位可将以下代码拷贝到idea等编译工具,
① pom.xml 中的依赖:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.2</version>
</dependency>
</dependencies>
② WordCountMapper:
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
/**
* Created by ygyblue2
*/
public class WordCountMapper extends Mapper {
Text k = new Text();
IntWritable v = new IntWritable(1);
@Override
protected void map(Object key, Object value, Context context) throws IOException, InterruptedException {
//1.将value转化为string
String line = value.toString();
//2.切分
String[] words = line.split(" ");
//3.写出
for (String word : words) {
k.set(word);
context.write(k,v);
}
}
}
③ WordCountReducer
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/**
* Created by ygyblue2
*/
public class WordCountReducer extends Reducer<Text,IntWritable,Text,IntWritable>{
IntWritable v = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
//1.累加
int sum = 0;
for ( IntWritable value : values){
sum += value.get();
}
//2.写出
context.write(key,v);
}
}
④ WordDriver
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
/**
* Created by ygyblue2
*/
public class WordDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
//1.获取job实体
Configuration configuration = new Configuration();
Job job = Job.getInstance(configuration);
//2.jar包所在路径
job.setJarByClass(WordDriver.class);
//3.设置自定义的mapper和reducer
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//4.设置mapper输出的kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//5.设置最终的输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//6.要出的文件所在路径
FileInputFormat.setInputPaths(job,new Path(args[0]));
//7.输出结果将要存放的路径
FileOutputFormat.setOutputPath(job,new Path(args[1]));
//8.提交(我们需要debug的部分),waitForCompletion内部同样调用submit()
boolean result = job.waitForCompletion(true);
//System.exit(result ? 0: 1);
}
}
2.在WordCountDriver的最后一行job.waitForCompletion除断点,运行debug并进入
---step Into 到submit();向下执行
进入submit()后首先比较重要的是this.connect(),connect方法通过构造Cluster对象来建立与集群的连接
setUseNewAPI将指引使用新版hadoopAPI接口
---step Into connect()
---Ctrl进入Cluster类构造器查看并断点
在CLuster初始化时会调用initialize(),此方法内部通过ClientProtocolProvider对象的creat()加载集群的配置文件,并会判断MapReduce运行在何种框架上来返回一个LocalJobRunner或YarnJobRunner协议对象(多态),继续向下执行会发现经过赋值最终client = clientProtocol , 所以local或是yarn的客户端本质即是JobRunner。initialize()的目的是通过加载配置类来创建客户端。
以上是connect()的主要内容,它主要内容就是①创建cluster集群对象 ②在cluster内部通过加载配置类创建客户端来建立连接
connect()执行完毕跳出后step over
getJobSubmitter()为提交Job的方法获取提交对象
使用提交对象对任务进行内部提交
---step into submitJobInternal()
---step into checkSpecs(job)
step over 并注意:
---step into checkOutputSpecs(job);
step over结束checkSpecs()跳出,经过上面的步骤可以了解到checkSpecs()是在校验我们设置的输出路径是否合法
继续step over会获取配置类/进行缓存步骤(跳过)
依照MapReduce的工作原理在验证输出路径合法后会开始进一步加载集群的配置信息准备开始读取文件
step over 到 InetAddress ip = InetAddress.getLocalHost();
观察Debugger的显示
此路径目前仍为空,但是可以在本地中找到此目录如下
继续step over
继续step over
此时还未创建这个拼接出的详细目录 , 这个地址目前只存在与内存中
继续step over 到 copyAndConfigureFiles
---step into copyAndConfigureFiles();
查看本地,确实存在此目录,这个目录就相当于job的工作空间,即将存放一些重要信息(三个: .split .jar .xml)至此完成创建job的工作空间
(我运行在本地,无需上传,如果运行在yarn的话可以继续step over至copyJar()方法详细了解Jar包上传的流程)
继续step over至跳出 , 经过以上的解读我们了解copyAndConfigureFile()完成的工作:①创建job的工作空间 ②向工作空间上传Jar包
继续step over 至 int maps = this.writeSplits(job, submitJobDir);
此方法内部会生成切片规划,此时我们查看job工作空间中 .split 文件的话会看到切片+序列化后的数据内容
继续step over至 writeConf();
此方法内部会读取我们hadoop的八个重要文件进行汇总(4个default.xml 和四个自定义的site.xml)并在工作空间生成job.xml文件
至此是Driver向yarn(或local)提交信息流程中的重要部分分析,在job向yarn提交后,yarn会根据此文件夹中的信息开始下一步工作如计算所需的maptask数量,启动Mr appmaster,nodemanager等
提交过程主要就是提交三个重要文件,分别由copyAndConfigureFile(),writesplit(),writeConf()提交jar包,split切片信息和job.xml配置信息