11

我在主机上运行 Cassandra 2.2.11(并且不会升级)。定期,在 cron 作业中,我运行nodetool命令进行监控。nodetool被实现为另一个使用 JMX 与 Cassandra java 进程对话的 java 进程。我每分钟启动五个左右的命令。

偶尔(不是以任何可识别的模式), 的执行nodetool将失败,并带有NoClassDefFoundError引用来自 的类的 a java.lang。例如,

java.lang.NoClassDefFoundError: java/lang/Thread (wrong name: java/lang/Thread)
    at java.lang.Class.getDeclaredFields0(Native Method)
    at java.lang.Class.privateGetDeclaredFields(Class.java:2583)
    at java.lang.Class.getDeclaredField(Class.java:2068)
    at java.util.concurrent.FutureTask.<clinit>(FutureTask.java:476)
    at java.util.concurrent.ScheduledThreadPoolExecutor.scheduleWithFixedDelay(ScheduledThreadPoolExecutor.java:590)
    at sun.rmi.transport.tcp.TCPChannel.free(TCPChannel.java:347)
    at sun.rmi.server.UnicastRef.free(UnicastRef.java:431)
    at sun.rmi.server.UnicastRef.done(UnicastRef.java:448)
    at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
    at com.sun.jndi.rmi.registry.RegistryContext.lookup(RegistryContext.java:132)
    at com.sun.jndi.toolkit.url.GenericURLContext.lookup(GenericURLContext.java:205)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at javax.management.remote.rmi.RMIConnector.findRMIServerJNDI(RMIConnector.java:1955)
    at javax.management.remote.rmi.RMIConnector.findRMIServer(RMIConnector.java:1922)
    at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:287)
    at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:270)
    at org.apache.cassandra.tools.NodeProbe.connect(NodeProbe.java:183)
    at org.apache.cassandra.tools.NodeProbe.<init>(NodeProbe.java:150)
    at org.apache.cassandra.tools.NodeTool$NodeToolCmd.connect(NodeTool.java:302)
    at org.apache.cassandra.tools.NodeTool$NodeToolCmd.run(NodeTool.java:242)
    at org.apache.cassandra.tools.NodeTool.main(NodeTool.java:158)

在此堆栈跟踪中,错误发生在FutureTask. 我也看过

java.lang.NoClassDefFoundError: java/lang/Object (wrong name: java/lang/Object)
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.getDeclaredMethod(Class.java:2128)
    at java.lang.invoke.MethodHandleImpl$Lazy.<clinit>(MethodHandleImpl.java:614)
    [...]

但是也

java.lang.NoClassDefFoundError: java/lang/String (wrong name: java/lang/String)
    at java.lang.Class.getDeclaredFields0(Native Method)
    at java.lang.Class.privateGetDeclaredFields(Class.java:2583)
    at java.lang.Class.getDeclaredField(Class.java:2068)
    at java.io.ObjectStreamClass.getDeclaredSUID(ObjectStreamClass.java:1703)
    at java.io.ObjectStreamClass.access$700(ObjectStreamClass.java:72)
    at java.io.ObjectStreamClass$2.run(ObjectStreamClass.java:484)
    at java.io.ObjectStreamClass$2.run(ObjectStreamClass.java:472)
    [...]

所以它不仅发生在类初始化期间,而且在我收集的几个示例中,反射实现中的某些东西似乎确实是罪魁祸首。

Java 版本为 8

java version "1.8.0_144"

启动器nodetool始终使用相同的类路径。那里没有奇怪的类(或额外的类加载器)。相同的安装在数百个相同的节点上完成(在 Linux 上)。

我的热门搜索结果NoClassDefFoundError wrong name指的是使用简化的类名来启动的执行java,而不是完全限定的名称。这不是这里的问题。此外,错误消息中的名称是相同的。

NoClassDefFoundError那么,什么会导致“引导”类出现这种“错误名称”错误呢?

4

3 回答 3

1

我认为这是导致连接器超时等问题的资源不足。您是否看到示例中的日志?nodeprobe 是通过 jmx 连接还是尝试连接然后出现错误?这些是非常典型的错误,也可能导致狗屎上的其他间歇性错误。(通常是 OS/netowrk OS 狗屎)因此:包括您的字符串甚至基于对象的错误;总之它是有道理的。发生错误时,您可能应该检查您的资源。我知道这是资源监视器导致资源不足的第 22 条问题;但它发生了呵呵

于 2017-11-02T10:31:15.623 回答
1

根据堆栈跟踪,在对getDeclaredFields0. 但是,这不是异常最初的来源。根据 OpenJDK 源代码,代码库中没有任何内容会在异常消息中引发带有“错误名称”的异常。消息来自其他地方。

我强烈怀疑这实际上是在重新报告第一次加载或初始化某个类时发生的问题。发生的情况是类加载器第一次发现问题,将有问题的内部类对象标记为“坏”,然后抛出错误。根据 javadoc,应用程序不应尝试从中恢复。但是,如果这样做,然后尝试以某种方式使用“坏”类,则原始问题将再次报告为NoClassDefFoundError原始原因。

那么原因是什么意思呢?

很难说,因为我们没有原始异常的堆栈跟踪;即然后是类加载/初始化第一次失败的地方。如果你能找到那个堆栈跟踪,我们就可以追踪做到这一点的第 3 方库。它几乎肯定发生在类加载器中。

显而易见的含义是类文件中的类名与类字节码中的名称不匹配。但是,我们需要检查类加载器代码以确定。

那么为什么会间歇性发生呢?

可能是因为应用程序 JVM 有许多类加载器,而其中只有一部分被这个坏类“污染”了他们的类命名空间。

那可能是个坏消息。这表明应用程序的核心可能存在某种同步问题。

无论如何,没有足够的证据得出合理的结论。

底线

根据证据,我这是某种“代码编织”或“字节码工程”出错的结果。作为进一步的猜测,我会说某些子类加载器没有正确委派,并且错误地尝试处理内置类。(甚至可能是有问题的类加载器知道它永远不应该处理“java.lang.*”类,并且它有一种模糊的说法。)

为什么?可能是因为某人/某事明确地将“rt.jar”添加到了它不应该在的某个类路径中。

为了进一步诊断,我们需要的第一件事是原始堆栈跟踪,它告诉我们哪个类加载器造成了初始损坏。

于 2017-11-04T23:15:33.647 回答
1

由于没有找到基本的java库,我认为你的java安装有问题或者你没有设置CLASSPATHJAVA_HOME环境变量。尝试设置CLASSPATHJAVA_HOME环境变量。

export JAVA_HOME="/usr/lib/jvm/java-8-oracle/bin"
export CLASSPATH="/usr/lib/jvm/java-8-oracle/lib"

如果不起作用,请尝试重新安装 java 并设置环境变量。

于 2017-11-04T15:25:20.530 回答