Class 在 运行 Hadoop 作业时加载问题

Class loading issue while running a Hadoop job

我有一个 C++ 服务,它公开了 2 个接口:

一个。 Submit():用于向 YARNRM

提交 DistCp 作业

b。 Query():用于查询应用程序的状态。

此服务在内部调用 Java 客户端(通过 JNI),它有 2 个静态函数:

  1. 提交()

  2. 查询()

提交() 做:

DistCp distCp = new DistCp(configuration, distCpOptions);
Job job = distCp.execute();
Parses the "application ID" from the tracking URL and returns it.

Query() 执行:

Takes "application ID" returned in Submit()
YarnClient yarnClient = YarnClient.createYarnClient();
yarnClient.init(new YarnConfiguration());
yarnClient.start();
yarnClient.getApplicationReport(applicationID); 
yarnClient.stop();

我面临的问题是,

  1. 如果对服务的第一次调用是 Submit(),则所有后续调用(Submit() 和 Query())都会成功
  2. 但是,如果对服务的第一次调用是 Query(),那么所有 Submit() 调用都会失败。

Query() 调用在所有条件下都成功。

Submit() 调用因错误而失败(下面的第 1 次调用、第 2 次调用和第 3 次调用,有不同的异常):

  1. java.util.ServiceConfigurationError: org.apache.hadoop.mapreduce.protocol.ClientProtocolProvider: Provider org.apache.hadoop.mapred.LocalClientProtocolProvider not found
  2. java.util.ServiceConfigurationError: org.apache.hadoop.mapreduce.protocol.ClientProtocolProvider: Provider org.apache.hadoop.mapred.YarnClientProtocolProvider not found
  3. java.io.IOException: Cannot initialize Cluster. Please check your configuration for mapreduce.framework.name and the correspond server addresses.

我调试了这个问题并发现,当首先调用 Query() API 时,然后 classes LocalClientProtocolProviderYarnClientProtocolProvider 没有被加载。当调用 Submit() 时,class 加载器应该加载这些 classes。但是,这并没有发生。

我还观察到,当首先调用 Query() API 时,Hadoop 配置发生了变化,并包含许多与 "mapreduce.*" 配置相关的默认设置。

我尝试在调用 Submit() 方法后立即使用 Class.forName() 显式加载。但是,这也无济于事。

调用 Submit() 时,为什么 class 加载程序不加载所需的 classes?这是 Hadoop 配置或 Java class 加载器的问题吗?还是因为我正在混合使用 MapReduce 和 Yarn APIs?

"mapreduce.framework.name"配置设置为"yarn".

我的环境是Hadoop 2.6.0.

我的class路径包含以下路径中存在的所有 Hadoop jar:

a. hadoop/common/    
b. hadoop/common/lib    
c. hadoop/hdfs/    
d. hadoop/hdfs/lib    
e. hadoop/mapreduce/    
f. hadoop/mapreduce/lib    
g. hadoop/yarn/
h. hadoop/yarn/lib

我发现,我正在混合使用 YarnMapReduce API,这导致了 class 加载问题。

当首先调用Query()时,它加载所有与YARN相关的classes。 例如:

org.apache.hadoop.yarn.client.api.YarnClient from file:/D:/data/hadoop-2
.6.0-SNAPSHOT/share/hadoop/yarn/hadoop-yarn-client-2.6.0-SNAPSHOT.jar

但是,MapReduce 相关的 classes 没有加载。例如,未加载以下 class:

org.apache.hadoop.mapred.YarnClientProtocolProvider from 
 file:/D:/data/hdoop-2.6.0-SNAPSHOT/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.6.0-SNAPSHOT.jar 

因此,当 Submit() 被调用时,class 加载程序假定它已经加载了所有必需的 classes。但是,classes YarnClientProtocolProviderLocalClientProtocolProvider 尚未加载。因此,Submit() 调用失败。

为了强制 class 加载程序加载所有 MapReduce 相关的 classes,我在 YarnClientWrapper 的构造函数中添加了以下语句(这是一个单例 class 并包装 YarnClient).

Cluster cluster = new Cluster(configuration);
cluster.getFileSystem();
cluster.close();

这解决了问题。

但是,更简洁的实施方式是在 Query() 中使用 MapReduce 客户端而不是 YarnClient。这将确保我们不会陷入 class 加载问题。