运行Hadoop作业时的类加载问题

时间:2015-09-30 14:18:42

标签: java hadoop java-native-interface classloader yarn

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

一个。提交():用于向YARNRM提交DistCp作业

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

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

  1. 提交()

  2. 查询()

  3. 提交()确实:

    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())SUCCEED
    2. 但是,如果第一次调用该服务是Query(),则所有Submit()调用FAIL。
    3. Query()调用在所有条件下都成功。

      Submit()调用失败并显示错误(第一次调用,第二次调用和第三次调用,但有不同的例外):

      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.
      4. 我调试了这个问题并发现,当首先调用Query()API时,不会加载类LocalClientProtocolProviderYarnClientProtocolProvider。当调用Submit()时,类加载器应该加载这些类。但是,这种情况并没有发生。

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

        一旦调用Submit()方法,我就尝试使用Class.forName()进行显式加载。但是,这也没有帮助。

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

        “mapreduce.framework.name”配置设置为“yarn”。

        我的环境是Hadoop 2.6.0。

        我的类路径包含以下路径中存在的所有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
        

1 个答案:

答案 0 :(得分:1)

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

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

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相关的类。例如,未加载以下类:

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()时,类加载器会假定它已加载了所有必需的类。但是,类YarnClientProtocolProviderLocalClientProtocolProvider尚未加载。因此,Submit()调用失败。

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

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

这解决了这个问题。

但是,更清晰的实施方法是在MapReduce而不是Query()中使用YarnClient客户端。这将确保我们不会进入类加载问题。