Java 在同一程序中处理两个版本的Hadoop时,Hadoop jar冲突问题
下面是我们遇到的当前Hadoop不兼容问题 用例 我们正在读取/扫描运行在新Hadoop(版本2.2.0.2.0.6.0-101[Hortonworks])上的HBASE(版本0.96.1.2.0.1-101-hadoop2),并使用JAVA程序写入旧Hadoop(版本0.20.2+320[Cloudera])。 但是,由于两个Hadoop版本之间的不兼容,我们遇到了异常 以下代码段引发异常:Java 在同一程序中处理两个版本的Hadoop时,Hadoop jar冲突问题,java,maven,hadoop,hbase,Java,Maven,Hadoop,Hbase,下面是我们遇到的当前Hadoop不兼容问题 用例 我们正在读取/扫描运行在新Hadoop(版本2.2.0.2.0.6.0-101[Hortonworks])上的HBASE(版本0.96.1.2.0.1-101-hadoop2),并使用JAVA程序写入旧Hadoop(版本0.20.2+320[Cloudera])。 但是,由于两个Hadoop版本之间的不兼容,我们遇到了异常 以下代码段引发异常: private HbaseConfigFactory(String clusterUri, Strin
private HbaseConfigFactory(String clusterUri, String hbaseRootdir) throws Exception {
factoryImpl = HBaseConfiguration.create();
factoryImpl.clear();
factoryImpl.set("hbase.zookeeper.quorum", clusterUri);
factoryImpl.set("zookeeper.znode.parent", hbaseRootdir);
// set the zookeeper port
String[] eles = clusterUri.split(":");
if (eles.length > 1) {
factoryImpl.set("hbase.zookeeper.property.clientPort", eles[1]);
}
try {
//THE BELOW CODE CAUSE THE EXCEPTION
HBaseAdmin.checkHBaseAvailable(factoryImpl);
} catch (Exception e) {
String message = String.format("HBase is currently unavailable: %s, %s",
e.getMessage(), e);
logger.error(message);
throw new Exception(e);
}
}
以下是例外情况:
private HbaseConfigFactory(String clusterUri, String hbaseRootdir) throws Exception {
factoryImpl = HBaseConfiguration.create();
factoryImpl.clear();
factoryImpl.set("hbase.zookeeper.quorum", clusterUri);
factoryImpl.set("zookeeper.znode.parent", hbaseRootdir);
// set the zookeeper port
String[] eles = clusterUri.split(":");
if (eles.length > 1) {
factoryImpl.set("hbase.zookeeper.property.clientPort", eles[1]);
}
try {
//THE BELOW CODE CAUSE THE EXCEPTION
HBaseAdmin.checkHBaseAvailable(factoryImpl);
} catch (Exception e) {
String message = String.format("HBase is currently unavailable: %s, %s",
e.getMessage(), e);
logger.error(message);
throw new Exception(e);
}
}
java.lang.Exception:java.lang.IllegalArgumentException:在org.apache.hadoop.security.UserGroupInformation中找不到方法getCurrentUser!
在com.shopping.writetold.HbaseConfigFactory.(HbaseConfigFactory.java:36)
位于com.shopping.writetold.HbaseConfigFactory.getInstance(HbaseConfigFactory.java:48)
位于com.shopping.writetold.WriteToHDFS.readDeals(WriteToHDFS.java:63)
位于com.shopping.writetold.WriteToHDFS.main(WriteToHDFS.java:50)
在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处
在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)中
在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)中
位于java.lang.reflect.Method.invoke(Method.java:601)
位于com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
原因:java.lang.IllegalArgumentException:在org.apache.hadoop.security.UserGroupInformation中找不到方法getCurrentUser!
位于org.apache.hadoop.hbase.util.Methods.call(Methods.java:45)
位于org.apache.hadoop.hbase.security.User.call(User.java:414)
位于org.apache.hadoop.hbase.security.User.callStatic(User.java:404)
位于org.apache.hadoop.hbase.security.User.access$200(User.java:48)
位于org.apache.hadoop.hbase.security.User$SecureHadoopUser。(User.java:221)
位于org.apache.hadoop.hbase.security.User$SecureHadoopUser。(User.java:216)
位于org.apache.hadoop.hbase.security.User.getCurrent(User.java:139)
位于org.apache.hadoop.hbase.client.HConnectionKey.(HConnectionKey.java:67)
位于org.apache.hadoop.hbase.client.HConnectionManager.getConnection(HConnectionManager.java:240)
位于org.apache.hadoop.hbase.client.HBaseAdmin.checkHBaseAvailable(HBaseAdmin.java:2321)
在com.shopping.writetold.HbaseConfigFactory.(HbaseConfigFactory.java:29)
... 8个以上
原因:java.lang.NoSuchMethodException:org.apache.hadoop.security.UserGroupInformation.getCurrentUser()
位于java.lang.Class.getMethod(Class.java:1624)
位于org.apache.hadoop.hbase.util.Methods.call(Methods.java:38)
... 还有18个
Maven依赖项:
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-core</artifactId>
<version>0.20.2</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>0.96.0-hadoop2</version>
</dependency>
org.apache.hadoop
hadoop内核
0.20.2
org.apache.hbase
hbase客户端
0.96.0-hadoop2
罐子细节
Maven:org.apache.hadoop:hadoop-common:2.1.0-beta
hadoop-common-2.1.0-beta.jar
类文件UserGroupInformation中的方法签名
public static synchronized org.apache.hadoop.security.UserGroupInformation getCurrentUser()抛出java.io.IOException
罐子细节
Maven:org.apache.hadoop:hadoop核心:0.20.2
hadoop-core-0.20.2.jar
类文件UserGroupInformation中的方法签名
静态javax.security.auth.Subject getCurrentUser()
两者具有相同的名称空间,即:
包org.apache.hadoop.security
当我有单独的程序从hbase读取数据并只使用各自的JAR写入cloudera HDFS时,它们工作得很好
在单个程序中是否有处理上述不兼容的解决方案
谢谢
Sagar B免责声明:作为先决条件,我认为更新到最新的统一Hadoop库是不可能的,但我对Hadoop几乎一无所知 本质上,您处于冲突中,因为在运行时,需要在类路径上同时使用两个库,这是一项艰巨的任务。为了在同一个VM中有两个来自不同来源的相同类,您需要至少使用两个不同的类加载器 从技术/架构的角度来看,在这个场景中要做的事情是将应用程序的两个部分解耦。或者在同一个VM中使用不同的类加载器运行,或者实际上将其作为使用共享机制交换消息的异构程序进行解耦(我想到了jms,但有很多替代方案) 由于您想探索单一虚拟机问题,因此面临两种选择。 手动执行或使用支持此操作的应用程序容器(OSGI)。无论哪种情况,您都需要至少在maven中解耦应用程序,以区分它们的依赖关系等 手动将意味着将应用程序的一部分放在当前类加载器中,然后从自定义类加载器中加载第二部分,因此假设写部分卸载在一个单独的jar中,创建一个自定义clasloader,加载旧的Hadoop jar(以及适用的转换)和这个单独的jar文件。相当技术性,但可行 我发现了一个使用java.util.ServiceLoader的参考问题,该问题可能会突出主题“使用自担风险”。()
另一个实际上正是出于这个原因而起作用的解耦解决方案是OSGI模型,它允许jar在pier层次结构中拥有自己独立的运行时依赖树,这本质上意味着同一个类可能存在于vm的多个版本中,因为它是每个jar的一个类加载器。然而,由于许多其他原因,OSGI是另一个猛兽,需要花费相当大的学习努力才能真正理解和利用。最好包括maven依赖树(mvn dependency:tree)的相关部分。您解决了这个问题吗?你能更新你的解决方案吗?非常感谢