Hadoop的classloader和libjars配置

Hadoop开发中必然会大量使用第三方的包,如Mahout、Hive等。在运行时,一个通用的做法是将第三方的包全部打包到当前项目中,和项目编译产生的classes文件一起,构建成一个巨大的jar包,然后直接运行这个包即可。

一般在eclipse中,可以使用ant来做打包工作,类似的ant文件如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project default="create_run_jar">
    <!--this file was created by Eclipse Runnable JAR Export Wizard-->
    <!--ANT 1.7 is required                                        -->
    <target>
        <copyfile dest="D:/hadoop/conf/config.mix.xml" src="https://www.linuxidc.com/D:/projects/up/recomm/src/config.mix.xml"/>
        <jar destfile="D:/hadoop/work/reckeyword.jar" filesetmanifest="mergewithoutmain">
            <manifest>
                <attribute value="com.sumsung.profile.analyze.keyword.mix.RecommenderDriver"/>
                <attribute value="."/>
            </manifest>
            <!--fileset dir="D:/projects/up/.metadata/.plugins/org.apache.hadoop.eclipse/hadoop-conf-5736823963924267363"/-->
            <zipfileset excludes="META-INFlicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicenselicense/**" src="https://www.linuxidc.com/D:/projects/up/recomm/mahout/xpp3_min-1.1.4c.jar"/>
            <fileset dir="D:/projects/up/recomm/classes"/>
         
        </jar>
    </target>
</project>

这样可以将所有jar包都打包到目标jar中,在hadoop中直接运行这个jar包即可。
如果hadoop是在本地或者局域网里面,那这么做是没问题的,但是如果hadoop是在远程,比如现在很多公司使用amazon提供的mapreduce,将mahout所有相关的类打包,形成最终的jar,至少在25兆以上,国内网速这么慢,每次调试都要耗费大量的时间。
解决方法是使用hadoop的libjar参数,通过这个参数来引入第三方的包,但是关于这个参数,在所有文档中说明都很简略。估计用的人也不多。
在hadoop中对这个参数解释:这是一个通用的参数,可以用来指定项目运行需要的第三方类库,不同的jar可以使用逗号分隔。(-libjars <comma seperated list of jars> Specify comma separated jar files to include in the classpath. )
如果在参数中使用-libjars来指定第三方类库,那hadoop会在什么时候加载这个类库?会放在哪个classloader中呢?这个需要参考到源代码,和libjars相关的代码。
首先,如果要使这个参数生效,必须使用ToolRunner来运行Job。因为相关代码是通过ToolRunner来调用GenericOptionsParser来实现的。

看一下GenericOptionsParser:
private void processGeneralOptions(Configuration conf,
      CommandLine line) {
  ......
    try {
      if (line.hasOption("libjars")) {
        conf.set("tmpjars",
                 validateFiles(line.getOptionValue("libjars"), conf));
        //setting libjars in client classpath
        URL[] libjars = getLibJars(conf);
        if(libjars!=null && libjars.length>0) {
          conf.setClassLoader(new URLClassLoader(libjars, conf.getClassLoader()));
          Thread.currentThread().setContextClassLoader(
              new URLClassLoader(libjars,
                  Thread.currentThread().getContextClassLoader()));
        }
      }
.....
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/7b5f58a0767202fb61c189f8361e2522.html