写MR程序时每每会使用到第三方包, 若是这些包在集群中不存在, 能够经过多种方式提交到集群供 MR 程序使用, 但若是集群中存在的jar与用户MR程序用到的JAR存在版本冲突时该如何解决?apache
下面是我碰到的问题及解决方式, 简单记录以下, 碰到一样问题的同窗能够参考下:app
昨天使用 commons-net-3.2.jar 包链接FTP采集日志,oop
调用方法片断:spa
FTPClient ftpClient = new FTPClient();.net
ftpClient.setConnectTimeout(1000);日志
// 这个方法在commons-net-3.2.jar包中有, 而在 commons-net-1.4.1.jar 中没有hadoop
通常状况下,使用hadoop jar 执行mr的时候,会首先加载$HADOOP_HOME/lib下的jar包,ci
因为使用的hadoop中带了commons-net-1.4.1.jar,因此会优先加载1.4.1版本,而忽略用户本身指定的3.2版本,因此报异常,get
Error: org.apache.commons.net.ftp.FTPClient.setConnectTimeout(I)Vinput
//异常提示调用setConnectTimeout 方法有问题。
/**
*/
static List getClassPaths(JobConf conf, File workDir,
TaskDistributedCacheManager taskDistributedCacheManager)
throws IOException {
// Accumulates class paths for child.
List classPaths = new ArrayList();
boolean userClassesTakesPrecedence = conf.userClassesTakesPrecedence();
// 这个参数项能够改变系统classpath加载的优先顺序, 默认应该是false
if (!userClassesTakesPrecedence) { // 默认是false, tasktrack机器的系统classpath老是优先加载
// start with same classpath as parent process
appendSystemClasspaths(classPaths);
}
// include the user specified classpath
appendJobJarClasspaths(conf.getJar(), classPaths);
// Distributed cache paths
if (taskDistributedCacheManager != null)
classPaths.addAll(taskDistributedCacheManager.getClassPaths());
// Include the working dir too
classPaths.add(workDir.toString());
if (userClassesTakesPrecedence) {
// parent process's classpath is added last
appendSystemClasspaths(classPaths);
}
return classPaths;
}
经过上面源码能够看出 参数项 -Dmapreduce.task.classpath.user.precedence 能够改变系统classpath加载的优先顺序
验证:
hadoop jar collect_log.jar com.collect.LogCollectJob -Dmapreduce.task.classpath.user.precedence=true -libjars commons-net-3.2.jar /new_log_collect/input /new_log_collect/output
程序执行成功。