编写实际生产用的hadoop mapreduce程序的时候,通常都会引用第三方库,也就会碰到ClassPath的问题,主要是两种情况:
一般会在两个阶段碰到,分别有不同的解决方法:
找不到类这种情况有两种解决方法:
使用maven打包,pom文件中打包插件设置如下:
maven-assembly-plugin
jar-with-dependencies
make-assembly
package
single
假如要将jackson-core-asl-1.9.13.jar库添加到HADOOP_CLASSPATH中:
export HADOOP_CLASSPATH=jackson-core-asl-1.9.13.jar
库加载顺序不对这种情况,那就是要让hadoop优先加载用户指定的库,设置如下的环境变量:
export HADOOP_USER_CLASSPATH_FIRST=true
这样设置之后可以解决问题的原因是,hadoop jar命令启动的程序的时候,会通过hadoop-config.sh来设置classpath,其中有段这样的设置代码:
if [[ ( "$HADOOP_CLASSPATH" != "" ) && ( "$HADOOP_USE_CLIENT_CLASSLOADER" = "" ) ]]; then
# Prefix it if its to be preceded
if [ "$HADOOP_USER_CLASSPATH_FIRST" != "" ]; then
CLASSPATH=${HADOOP_CLASSPATH}:${CLASSPATH}
else
CLASSPATH=${CLASSPATH}:${HADOOP_CLASSPATH}
fi
fi
也就是说如果HADOOP_CLASSPATH不为空且HADOOP_USER_CLASSPATH_FIRST不为空的时候,会将HADOOP_CLASSPATH指定的类库优先加载。
找不到类这种情况,通过-libjars指定引用的库,hadoop将这里指定的库上传到DistributedCache中,然后添加到task运行的classpath。
库加载顺序的问题,可以通过设置Configuration类解决。
conf.set("mapreduce.job.user.classpath.first","true");
conf.set("mapreduce.task.classpath.user.precedence","true");
或者
String cp = "$PWD/*:hadoop自身的类库目录";
conf.set(YarnConfiguration.YARN_APPLICATION_CLASSPATH, cp);
这里hadoop自身的类库目录,是指你运行程序所在的hadoop集群的所有类库目录。
具体原因可以参考这篇文章:Hadoop程序JAR包冲突的分析及解决方法。