Hadoop - Map/Reduce 通过理解org.apache.hadoop.mapreduce.Job类来学习hadoop的执行逻辑

本文深入探讨了Hadoop Job类的使用方法及执行逻辑,从创建Job实例、设置参数到启动Job完成任务执行的全过程进行了详细阐述。重点介绍了如何通过Job类设置Mapper、Combiner、Reducer等关键组件,以及Job执行过程中的内部流程,包括Inputformat的读取与切分、Mapper和Reducer的任务调度等。

在我的上篇文章“Hadoop - Map/Reduce 通过WordCount例子的变化来了解新版hadoop接口的变化”中,已经跟大家提到,在Hadoop新的版本中,使用org.apache.hadoop.mapreduce.Job类替代了JobClient类。现在,我想通过对于了解Job来学习hadoop的调用逻辑。


首先,我们来回顾一下,在wordcount例子中,main函数通过创建Job类,并给Job实例设置相应的值,最终调用waitForCompletion函数来执行Job。

    Job job = new Job(conf, "word count");
    job.setJarByClass(WordCount.class);
    job.setMapperClass(TokenizerMapper.class);
    job.setCombinerClass(IntSumReducer.class);
    job.setReducerClass(IntSumReducer.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(IntWritable.class);
    FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
    FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
    System.exit(job.waitForCompletion(true) ? 0 : 1);

Job类本身是继承自JobContextImpl,并实现了JobContext接口。JobContextImpl是JobContext接口的一个简单实现,给Job类中的相关方法提供了一系列的默认实现。

Job类本身提供的构造函数如下:

Job()
Job(Configuration)
Job(Configuration, String)
Job(Cluster)
Job(Cluster, Configuration)
Job(Cluster, JobStatus, Configuration)

在前3个构造函数的实现中,最终会由configuration生成新的cluster类,从而调用第5个构造函数,而第4和第6个构造函数也会调用第5个构造函数,因此,第5个构造函数是实际上Job类构造的实现。Cluster类提供了访问map/reduce cluster的一系列方法。而Configuration类提供了对于配置信息的访问方法。

除了上面列出的构造函数,Job类还提供了一系列对应的工厂方法:

getInstance()
getInstance(Configuration)
getInstance(Configuration, String)
getInstance(Cluster)
getInstance(Cluster, Configuration)
getInstance(Cluster, JobStatus, Configuration)

现在,我们已经得到了一个Job类实例,接下来就是要给Job类设值相应的属性,从而使Job能够正确的执行。这里,我们就以wordcount例子中的方法为例来说明:

1. job.setJarByClass(WordCount.class)

在Java doc中,对于这个function的注释是:Set the Jar by finding where a given class came from.

同时,Job类还提供另外一个方法,直接设值Job的Jar文件:setJar(String jar),通过指定全路径,直接设值Job的jar文件。


2. job.setMapperClass(TokenizerMapper.class);

该方法用来设置Job的Mapper,这里,输入的参数应该是一个Mapper类的子类的class属性。


3.     job.setCombinerClass(IntSumReducer.class);

Set the combiner class for the job


4.     job.setReducerClass(IntSumReducer.class);

 Set the Reducer for the job.


5.     job.setOutputKeyClass(Text.class);

 Set the key class for the job output data.


6.     job.setOutputValueClass(IntWritable.class);

Set the value class for job outputs.


7.     FileInputFormat.addInputPath(job, new Path(otherArgs[0]));

这里,我们要注意,FileInputFormat的全路径是org.apache.hadoop.mapreduce.lib.input.FileInputFormat,因为原来也有一个FileInputFormat在mapred包下面,那个类已经是Deprecated的类,在新的版本当中,采用org.apache.hadoop.mapreduce.lib.input.FileInputFormat来替换。addInputPath函数将输入的path加入到job的INPUT_DIR中去。FileInputFormat类提供了几个类似的类来实现相关的功能,如:setInputPaths(Job, String),addInputPaths(Job, String),setInputPaths(Job, Path...),addInputPath(Job, Path)


8.     FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

org.apache.hadoop.mapreduce.lib.output.FileOutputFormat用setOutputPath方法给Job设置输出目录。


到此为止,我们已经给Job实例设置了足够的属性,我们现在可以启动Job来完成我们预想的功能了。

Job类中提供了两种启动Job的方式:

1. submit()

submit函数会把Job提交给对应的Cluster,然后不等待Job执行结束就立刻返回。同时会把Job实例的状态设置为JobState.RUNNING,从而来表示Job正在进行中。然后在Job运行过程中,可以调用getJobState()来获取Job的运行状态。
2. waitForCompletion(boolean)

waitForCompletion函数会提交Job到对应的Cluster,并等待Job执行结束。函数的boolean参数表示是否打印Job执行的相关信息。返回的结果是一个boolean变量,用来标识Job的执行结果。


到目前为止,我们针对wordcount例子,介绍了一个Job从创建,到设置参数,到执行的整个过程。但是hadoop的执行Job的时,内部又是怎么样一个流程呢?

1. Inputformat会从job的INPUT_DIR目录下读入待处理的文件,检查输入的有效性并将文件切分成InputSplit列表。Job实例可以通过setInputFormatClass(Class<? extends InputFormat>)函数来设置所需的inputformat。

2. 当Inputformat对输入文件分片后,会对每个分片构建一个MapperTask实例(MapTask(String, TaskAttemptID, int, TaskSplitIndex, int))。其实整个Mapper类的调度过程,都是由MapperTask来实现的。MapperTask的run(JobConf, TaskUmbilicalProtocol)方法实现了对于Mapper task调度的整个过程。

2.1  RecordReader会解析InputSplit,生成对应的key/value pair。Inputformat中有一个除了用于分片的getSplits(JobContext)方法外,还有一个方法createRecordReader(InputSplit, TaskAttemptContext),该方法用于给每一个分片创建一个RecordReader。重写这个方法,可以添加自己的RecordReader。

2.2 Mapper类会对属于一个InputSplit所有key/value pair调用一次map函数。关于Mapper类的作用,在Java doc中描述如下:“Mapper maps input key/value pairs to a set of intermediate key/value pairs”。 Job实例可以通过setMapperClass(Class<? extends Mapper>)函数来设置自己的Mapper类。

2.3 可以通过Job实例的setSortComparatorClass(Class<? extends RawComparator>)方法来为Mapper设定一个Comparator class,用来对Mapper的结果根据key进行排序。

2.4 可以通过Job实例的setPartitionerClass(Class<? extends Partitioner>)方法来为Mapper设定一个Partitioner Class,用来对Mapper的结果根据Reducer进行分片。

2.5 可以通过Job实例的setCombinerClass(Class<? extends Reducer>)方法为Mapper设定一个Combiner Class,用来在本地进行聚集操作,从而减少从Mapper到Reducer的数据传输量。

3. 在Mapper执行结束之后,ReducerTask类会被用来进行整个Reducer操作的调度

3.1 Shuffle类会被调用从而来获取在Mapper输出中属于本Reducer的分片,并将多个分片combine成一个。

3.2 Shuffle类会使用MergeManager根据Job实例的setSortComparatorClass(Class<? extends RawComparator>)所设定的Comparator class对key/value pair进行排序

3.3 在shuffle操作执行结束之后,如果对于Reducer的input数据,有使用特殊分组的需求的话,可以通过Job实例的setGroupingComparatorClass(Class<? extends RawComparator>)方法来实现定制的分组策略,否则,则使用setSortComparatorClass(Class<? extends RawComparator>)的比较方式。

3.4 在分组后的结果中,针对每一个<key, (list of values)> pair 调用Reduce的reduce(K2, Iterator<V2>, OutputCollector<K3, V3>, Reporter)方法。可以通过Job实例的setReducerClass(Class<? extends Reducer>)方法类设置相应的Reduce实现。

4.  Reduce 的结果将由OutputCollector.collect(WritableComparable, Writable)写入文件系统


以上,是我参照Hadoop的文档,对照hadoop的源码,以及自己的一点分析。


tar: hadoop-3.3.6: Cannot mkdir: Permission denied tar: hadoop-3.3.6/share/doc/hadoop/hadoop-mapreduce-client/hadoop-mapreduce-client-app/apidocs/org/apache/hadoop/mapreduce/jobhistory/class-use: Cannot mkdir: No such file or directory hadoop-3.3.6/share/doc/hadoop/hadoop-mapreduce-client/hadoop-mapreduce-client-app/apidocs/org/apache/hadoop/mapreduce/jobhistory/class-use/JobHistoryEventHandler.MetaInfo.html tar: hadoop-3.3.6: Cannot mkdir: Permission denied tar: hadoop-3.3.6/share/doc/hadoop/hadoop-mapreduce-client/hadoop-mapreduce-client-app/apidocs/org/apache/hadoop/mapreduce/jobhistory/class-use/JobHistoryEventHandler.MetaInfo.html: Cannot open: No such file or directory hadoop-3.3.6/share/doc/hadoop/hadoop-mapreduce-client/hadoop-mapreduce-client-app/apidocs/org/apache/hadoop/mapreduce/jobhistory/class-use/JobHistoryEventHandler.html tar: hadoop-3.3.6: Cannot mkdir: Permission denied tar: hadoop-3.3.6/share/doc/hadoop/hadoop-mapreduce-client/hadoop-mapreduce-client-app/apidocs/org/apache/hadoop/mapreduce/jobhistory/class-use/JobHistoryEventHandler.html: Cannot open: No such file or directory hadoop-3.3.6/share/doc/hadoop/hadoop-mapreduce-client/hadoop-mapreduce-client-app/apidocs/org/apache/hadoop/mapreduce/jobhistory/class-use/JobHistoryEvent.html tar: hadoop-3.3.6: Cannot mkdir: Permission denied tar: hadoop-3.3.6/share/doc/hadoop/hadoop-mapreduce-client/hadoop-mapreduce-client-app/apidocs/org/apache/hadoop/mapreduce/jobhistory/class-use/JobHistoryEvent.html: Cannot open: No such file or directory
最新发布
09-28
<think>嗯,用户遇到了在解压Hadoop时出现的权限和路径问题。让我仔细想想用户的需求场景——用户应该是在Linux环境下尝试安装Hadoop 3.3.6,但被系统权限和目录校验拦住了。从用户引用的材料来看,用户似乎有一定Linux基础但可能对权限管理不够熟悉。 注意到引用[1]明确提到了解压命令的参数,但没提权限问题;引用[2][3]都指向Windows下的权限错误,这和用户当前环境不符;而引用[4][5]展示了环境变量配置的重要性,这可能间接相关。用户真正需要的不是这些引用内容,而是针对tar命令的具体排错方案。 用户的核心痛点有两个:Permission denied和No such file or directory。前者需要权限提升或归属权调整,后者需要路径校验。考虑到用户正在操作/opt目录,这通常需要sudo权限。我想到四个关键解决层次: 首先要确认目标目录/opt/app是否存在——如果不存在自然要创建,且必须用sudo创建 其次检查当前用户是否有opt/app的写权限,可能需要用ls -ld查看 然后解压命令本身可能需要sudo前缀,特别是当用户不属于root组时 最后解压后的文件归属权问题,用chown解决 特别要注意-C参数后的路径必须绝对存在,这点在引用[1]的示例里体现为/opt/app目录。如果用户漏掉了这个目录创建步骤,就会触发第二个错误。另外,用户引用的[4]提到环境变量,虽然不直接相关,但提示我后续需要提醒用户配置HADOOP_HOME。 用户的操作环境很可能不是root账户而是普通用户,所以sudo会成为关键。在回复时需要强调危险操作前的备份提醒,比如建议先备份安装包。考虑到Hadoop安装的连续性,还应该补充环境变量配置的建议,这样用户完成解压后就能顺利进入下一步配置。 对了,用户引用的错误案例里有Windows路径的斜杠问题,虽然当前是Linux环境,但还是要提醒用户注意tar命令里路径分隔符必须用正斜杠。最后用分层步骤+代码块呈现解决方案最清晰,每个步骤配简要说明,比如创建目录时解释-p参数防父目录缺失的功能。 </think>针对使用 `tar` 解压 Hadoop-3.3.6 时出现的 **Permission denied** 和 **No such file or directory** 问题,以下是系统性的解决方案: --- ### **问题原因与解决方法** #### 1. **No such file or directory(目录不存在)** - **原因**:`-C` 参数指定的目标目录(如 `/opt/app`)未创建。 - **解决**: ```bash # 创建目标目录(需sudo权限) sudo mkdir -p /opt/app # 验证目录是否存在 ls -ld /opt/app ``` > **说明**: > `-p` 参数确保自动创建父目录[^1]。 #### 2. **Permission denied(权限不足)** - **原因**:当前用户对 `/opt/app` 或压缩文件无操作权限。 - **解决**: ```bash # 方案1:使用sudo执行解压(推荐) sudo tar -zxvf /opt/soft/hadoop-3.3.6.tar.gz -C /opt/app # 方案2:更改目标目录所有者 sudo chown -R $USER:$USER /opt/app # 将目录归属当前用户 tar -zxvf /opt/soft/hadoop-3.3.6.tar.gz -C /opt/app # 方案3:赋予用户写权限 sudo chmod -R u+w /opt/app # 给当前用户添加写权限 ``` #### 3. **文件路径错误** - **验证压缩包路径是否正确**: ```bash ls -l /opt/soft/hadoop-3.3.6.tar.gz # 检查文件是否存在 ``` > 若路径错误,修正为实际路径(如 `/home/user/downloads/...`)。 --- ### **完整操作流程** ```bash # 1. 创建目标目录(需sudo) sudo mkdir -p /opt/app # 2. 赋予当前用户操作权限 sudo chown -R $USER:$USER /opt/app # 3. 解压文件(权限足够时可省略sudo) tar -zxvf /opt/soft/hadoop-3.3.6.tar.gz -C /opt/app # 4. 验证解压结果 ls /opt/app/hadoop-3.3.6 ``` --- ### **关键注意事项** 1. **权限层级**: - `/opt` 属系统目录,默认需 root 权限操作。 - 若需避免频繁用 `sudo`,可将目录所有权移交普通用户: ```bash sudo chown -R $USER:$USER /opt/app ``` 2. **路径规范**: - 使用绝对路径(如 `/opt/app`),避免相对路径歧义。 3. **后续配置**: - 解压后需设置环境变量(引用[4]): ```bash export HADOOP_HOME=/opt/app/hadoop-3.3.6 export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin ``` --- **
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值