所以我试图在通过Oozie工作流启动的Yarn集群模式下运行Spark作业,但遇到了以下错误(下面是相关的堆栈)
java.sql.SQLException: ERROR 103 (08004): Unable to establish connection.
at org.apache.phoenix.exception.SQLExceptionCode$Factory$1.newException(SQLExceptionCode.java:388)
at org.apache.phoenix.exception.SQLExceptionInfo.buildException(SQLExceptionInfo.java:145)
at org.apache.phoenix.query.ConnectionQueryServicesImpl.openConnection(ConnectionQueryServicesImpl.java:296)
at org.apache.phoenix.query.ConnectionQueryServicesImpl.access$300(ConnectionQueryServicesImpl.java:179)
at org.apache.phoenix.query.ConnectionQueryServicesImpl$12.call(ConnectionQueryServicesImpl.java:1917)
at org.apache.phoenix.query.ConnectionQueryServicesImpl$12.call(ConnectionQueryServicesImpl.java:1896)
at org.apache.phoenix.util.PhoenixContextExecutor.call(PhoenixContextExecutor.java:77)
at org.apache.phoenix.query.ConnectionQueryServicesImpl.init(ConnectionQueryServicesImpl.java:1896)
at org.apache.phoenix.jdbc.PhoenixDriver.getConnectionQueryServices(PhoenixDriver.java:180)
at org.apache.phoenix.jdbc.PhoenixEmbeddedDriver.connect(PhoenixEmbeddedDriver.java:132)
at org.apache.phoenix.jdbc.PhoenixDriver.connect(PhoenixDriver.java:151)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:208)
...
Caused by: java.io.IOException: java.lang.reflect.InvocationTargetException
at org.apache.hadoop.hbase.client.ConnectionFactory.createConnection(ConnectionFactory.java:240)
at org.apache.hadoop.hbase.client.ConnectionManager.createConnection(ConnectionManager.java:414)
at org.apache.hadoop.hbase.client.ConnectionManager.createConnectionInternal(ConnectionManager.java:323)
at org.apache.hadoop.hbase.client.HConnectionManager.createConnection(HConnectionManager.java:144)
at org.apache.phoenix.query.HConnectionFactory$HConnectionFactoryImpl.createConnection(HConnectionFactory.java:47)
at org.apache.phoenix.query.ConnectionQueryServicesImpl.openConnection(ConnectionQueryServicesImpl.java:294)
... 28 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.apache.hadoop.hbase.client.ConnectionFactory.createConnection(ConnectionFactory.java:238)
... 33 more
Caused by: java.lang.UnsupportedOperationException: Unable to find org.apache.hadoop.hbase.ipc.controller.ClientRpcControllerFactory
at org.apache.hadoop.hbase.util.ReflectionUtils.instantiateWithCustomCtor(ReflectionUtils.java:36)
at org.apache.hadoop.hbase.ipc.RpcControllerFactory.instantiate(RpcControllerFactory.java:58)
at org.apache.hadoop.hbase.client.ConnectionManager$HConnectionImplementation.createAsyncProcess(ConnectionManager.java:2317)
at org.apache.hadoop.hbase.client.ConnectionManager$HConnectionImplementation.<init>(ConnectionManager.java:688)
at org.apache.hadoop.hbase.client.ConnectionManager$HConnectionImplementation.<init>(ConnectionManager.java:630)
... 38 more
Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.hbase.ipc.controller.ClientRpcControllerFactory
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at org.apache.hadoop.hbase.util.ReflectionUtils.instantiateWithCustomCtor(ReflectionUtils.java:32)
... 42 more
一些背景信息:
- 该作业在spark 1.4.1上运行(在spark.conf文件中指定了正确的spark.yarn.jar字段)
- oozie.libpath设置为我的程序的jar所在的hdfs目录
- 在phoenix-4.5.1-hbase-1.0-client.jar中存在找不到的类org.apache.hadoop.hbase.ipc-controller.ClientRpcControllerFactory。我在spark.conf文件中的spark.driver.extraClassPath和spark.executer.extracClassPath中指定了这个jar。我还在pom文件中添加了phoenix核心依赖项,因此该类也存在于我的着色项目jar中
迄今为止的观察结果:
- 在我的spark.conf文件spark.driver.userClassPathFirst中添加一个额外的字段并将其设置为true可以消除classnotfound异常。但是,它也阻止我初始化spark上下文(空指针异常)。从谷歌上搜索,似乎包括这个字段会打乱类路径,所以可能不是这样做的方法,因为我甚至不能用这种方式初始化火花上下文
- 我注意到在oozie stdout日志中,我没有看到phoenix jar的类路径。因此,也许出于某种原因,spark.driver.extraClassPath和spark.executer.extracClassPath实际上并没有将jar作为extraClassPath?我知道我正在指定正确的jar文件路径,因为其他作业都有具有相同参数的spark.conf文件
- 我找到了一种巧妙的方法,通过将phoenix jar复制到与我的程序jar所在的目录相同的目录中,使其显示在类路径中(在oozie stdout日志中)。无论spark.executer.extraClassPath是否更改为指向新的jar位置,这都有效。然而,classnotfound异常仍然存在,尽管我在解压jar时清楚地看到了ClientRpcControllerFactory jar)
我尝试过的其他东西:
- 我尝试使用sparkConf.setJars()和sparkContext.addJar()方法,但仍然遇到相同的错误
- 在我的作业属性文件中的spark.driver.extraClassPath字段中添加了jar,但似乎没有帮助(spark文档指出,在客户端模式下运行时,该字段是必要的,因此可能与我的情况无关)
如有任何帮助/想法/建议,我们将不胜感激。
我使用CDH 5.5.1+Phoenix 4.5.2(均与包裹一起安装),并面临相同的问题。我想问题在我切换到客户端模式后就消失了。我无法验证这一点,因为我现在在集群模式中遇到了其他错误。
我试图追踪Phoenix的源代码,发现了一些有趣的东西。希望Java/Scala专家能够找出根本原因。
- 已加载
PhoenixDriver
类。这表明罐子最初是被发现的。分层装载机之后/上下文切换(?),jar从类路径中丢失 -
如果
Class.forName()
是程序中不存在的类,则不需要调用sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
。堆栈类似于:java.lang.ClassNotFoundException: NONEXISTINGCLASS at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:264)
-
我将Phoenix代码复制到我的程序中进行测试。如果我调用
ConnectionQueryServicesImpl.init (ConnectionQueryServicesImpl.java:1896)
,我仍然得到ClassNotFoundExcpetion
。但是,对ConnectionQueryServicesImpl.openConnection (ConnectionQueryServicesImpl.java:296)
的调用返回了可用的HBase连接。看起来PhoenixContextExecutor
造成了罐子的丢失,但我不知道是怎么回事。
Cloudera Phoenix 4.5.2源代码:https://github.com/cloudera-labs/phoenix/blob/phoenix1-4.5.2_1.2.0/phoenix-core/src/main/java/org/apache/
(不确定我是否应该发表评论…但我无论如何都没有声誉)
所以我设法解决了我的问题并运行了我的作业。我的解决方案很粗糙,但会在这里发布,以防将来帮助其他人。
基本上,据我所知,问题是负责查找ClientRpcControllerFactory
类的org.apache.hadoop.hbase.util.ReflectionUtils
类是从集群中的某个cloudera目录加载的,而不是从我自己的jar加载的。当我将spark.driver.userClassPathFirst
设置为true时,它优先从我的jar加载ReflectionUtils类,因此能够定位ClientRpcControllerFactory
类。但是,当我尝试初始化SparkContext时,这弄乱了其他一些类路径,并不断给我一个NullPointerException,所以我寻找另一个解决方案。
我试图弄清楚是否可以将所有默认的cdh jar排除在我的类路径中,但发现spark.yarn.jar中的值正在拉入所有这些cdh jar,我肯定需要指定那个jar。
因此,解决方案是将Phoenix jar中org.apache.hadoop.hbase
下的所有类都包含到spark assembly jar(spark.yarn.jar指向的jar)中,这消除了最初的异常,并且在尝试初始化SparkContext时没有给我NPE。我发现现在ReflectionUtils
类是从spark assembly jar加载的,由于ClientRpcControllerFactory
也包含在那个jar中,所以它能够找到它。之后,我又遇到了一些Phoenix类的classNotFoundException,所以我也把这些类放进了spark assemble jar中。
最后,我遇到了一个java.lang.RuntimeException: hbase-default.xml File Seems to be for and old Version of HBase
问题。我发现我的应用程序jar包含这样一个文件,但将hbase.defaults.for.version.skip
更改为true并没有起到任何作用。因此,我在spark assembly jar中包含了另一个hbase-default.xml文件,其中的skip标志为true,它终于工作了。
一些观察:
- 我注意到我的spark汇编jar完全缺少org.apache.hadoop.hbase目录。一位同事告诉我,通常我应该在我的spark组装jar中找到一个hbase目录,所以也许我使用的是一个坏的spark装配jar。编辑:我检查了一个新下载的spark assembly jar(v1.5.2),但它没有,所以它可能不包括apache.hadoop.hbase包
- ClassNotFoundException和类加载器问题很难调试