Yarn集群模式下Spark作业的ClassNotFoundException



所以我试图在通过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专家能够找出根本原因。

  1. 已加载PhoenixDriver类。这表明罐子最初是被发现的。分层装载机之后/上下文切换(?),jar从类路径中丢失
  2. 如果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)
    
  3. 我将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和类加载器问题很难调试

相关内容

  • 没有找到相关文章