【问题标题】:Use external Native Libraries (.so) and external jar with Hadoop MapReduce将外部本机库 (.so) 和外部 jar 与 Hadoop MapReduce 一起使用
【发布时间】:2014-11-16 17:49:16
【问题描述】:

我是 hadoop / java 世界的新手,所以请保持温和,随时纠正严重错误。 我正在尝试使用在本地运行 Hadoop(独立模式)的 ubuntu 机器上编译的本机库。除了我编译的 .jar 之外,我还尝试使用外部 .jar。我尝试制作 fatjar 失败,并决定尝试通过命令行将外部 jar 和本机库传递给 hadoop。这些库用于我创建的自定义记录阅读器。我可以通过 hadoop 命令在没有外部库的情况下运行 mapreduce 作业。当我设置 LD_LIBRARY_PATH 类变量时,我也可以在 Eclipse 中运行这个程序。我不确定需要设置哪些变量才能在 hadoop 中成功运行此作业,所以请告诉我是否需要一些变量,尽管我已尝试设置 $HADOOP_CLASSPATH。

./bin/hadoop jar ~/myjar/cdf-11-16.jar CdfInputDriver -libjars cdfjava.jar -files libcdf.so,libcdfNativeLibrary.so input output

我尝试从本地访问 jar 和 so 文件并将它们复制到 HDFS。

我从作业中收到以下错误:

Exception in thread "main" java.lang.NoClassDefFoundError: gsfc/nssdc/cdf/CDFConstants
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:274)
    at org.apache.hadoop.conf.Configuration.getClassByNameOrNull(Configuration.java:1844)
    at org.apache.hadoop.conf.Configuration.getClassByName(Configuration.java:1809)
    at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:1903)
    at org.apache.hadoop.mapreduce.task.JobContextImpl.getInputFormatClass(JobContextImpl.java:174)
    at org.apache.hadoop.mapreduce.JobSubmitter.writeNewSplits(JobSubmitter.java:490)
    at org.apache.hadoop.mapreduce.JobSubmitter.writeSplits(JobSubmitter.java:510)
    at org.apache.hadoop.mapreduce.JobSubmitter.submitJobInternal(JobSubmitter.java:394)
    at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1285)
    at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1282)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:415)
    at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1614)
    at org.apache.hadoop.mapreduce.Job.submit(Job.java:1282)
    at org.apache.hadoop.mapreduce.Job.waitForCompletion(Job.java:1303)
    at CdfInputDriver.run(CdfInputDriver.java:45)
    at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)
    at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:84)
    at CdfInputDriver.main(CdfInputDriver.java:50)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.hadoop.util.RunJar.main(RunJar.java:212)
Caused by: java.lang.ClassNotFoundException: gsfc.nssdc.cdf.CDFConstants
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    ... 36 more

我尝试使用以下代码查看文件是否已加载到缓存中,并且它“缓存文件:”打印为 null:

public class CdfInputDriver extends Configured implements Tool{

    @Override
    public int run(String[] args) throws Exception {

        Job job = Job.getInstance(getConf());

        System.out.println("cache files:" + getConf().get("mapreduce.job.cache.files"));
        Path[] uris = job.getLocalCacheFiles();
        for(Path uri: uris){

              System.out.println(uri.toString());
              System.out.println(uri.getName());            

        } 
        job.setJarByClass(getClass());

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);

        job.setInputFormatClass(CdfInputFormat.class);
        job.setOutputFormatClass(TextOutputFormat.class);

        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        job.setMapperClass(CdfMapper.class);
        //job.setReducerClass(WordCount.IntSumReducer.class);

        return job.waitForCompletion(true) ? 0 : 1;
    }

    public static void main(String[] args)  throws Exception,
        InterruptedException, ClassNotFoundException {
        int exitCode = ToolRunner.run(new CdfInputDriver(), args);
        System.exit(exitCode);
    }
}

另外,我只是为了不可避免地在 Amazon EMR 上运行该作业进行测试。将 .so 和 .jar 存储在 S3 上并使用类似的方法理论上可行吗?

感谢任何帮助!

【问题讨论】:

    标签: java hadoop


    【解决方案1】:

    我为对此有问题的人解决了这个问题。在我的场景中,这是多个问题的组合。

    ./bin/hadoop jar ~/myjar/cdf-11-16.jar CdfInputDriver -libjars cdfjava.jar -files libcdf.so,libcdfNativeLibrary.so input output
    

    有几件事让我陷入了困境。这是我检查的一些内容。如果有人知道为什么这些有助于它工作的事实信息,我们将不胜感激。

    (对于 linux 新手)如果您使用 sudo 运行 hadoop,请确保包含 -E 以包含环境变量。

    确保第三方 .jar 库位于您的主节点上。 (似乎是必要的,但尚未通过文档确认......否则我的环境变量可能不正确)

    我能够使用 Amazon EMR 运行它。我将.so文件和.jars上传到s3,ssh'd到集群的主节点,通过http://blog.adaptovate.com/2013/06/installing-s3cmd-on-ec2-so-that-yum.html安装s3cmd,复制cdf-11-16.jar(mapreduce jar)和cdfjava.jar(第三方jar)使用 s3cmd get 到主节点,然后运行作业。我能够在 S3 上引用 .so 文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-06
      • 2015-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多