Zookeeper不停打印错误日志NoClassDefFoundError原因排查,ConnectRequest

时间:2023-01-19 21:21:52
最近发现联调环境上,某web应用日志频繁报下面的错误:
2017-01-11 13:48:51.619  WARN 385 --- [68.124.11:2181)] org.apache.zookeeper.ClientCnxn          : Session 0x0 for server 10.168.124.11/10.168.124.11:2181, unexpected error, closing socket connection and attempting reconnect

java.lang.NoClassDefFoundError: org/apache/zookeeper/proto/ConnectRequest
at org.apache.zookeeper.ClientCnxn$SendThread.primeConnection(ClientCnxn.java:857) ~[zookeeper-3.4.6.jar!/:3.4.6-1569965]
at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:363) ~[zookeeper-3.4.6.jar!/:3.4.6-1569965]
at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1081) ~[zookeeper-3.4.6.jar!/:3.4.6-1569965]


虽然web服务也能正常执行,但log日志一直不停地打,这肯定是不行的。刚开始看到NoClassDefFoundError这个错,以为又是缺包少类,或者jar包冲突。但是这个类是ZK的核心包里的类,按道理不应该会没有jar包。况且NoClassDefFoundError和NoClassException多少还是有些区别的

于是胸有成竹自以为是jar包冲突,就把spring-boot打的web-jar包解开,结果lib目录下,仅有一个zookeeper-3.4.6.jar,还有一个zkCLient的jar包。于是jar包冲突被排除了。 

无奈,只能在网上寻觅答案了。搜索了一会,网上只能找到下面的错误排查原因:


  1. java.lang.NoClassDefFoundError: org/apache/zookeeper/proto/SetWatches

   看了看里面介绍的详细原因:(原文请参看:http://blog.csdn.net/hengyunabc/article/details/41450003)
    这个异常的原因,是某些zookeeper的类没有加载到。

最终原因分析

梳理下整个流程:

  1. Tomcat启动,初始化webcontext;
  2. 初始化spring, spring初始某些些bean,这些bean包括了zookeeper的连接相关的bean;
  3. 这时zkClient(独立线程)已经连接上服务器了,但是classloader没有加载到org/apache/zookeeper/proto/SetWatches类;
  4. spring初始化失败,导致Tomcat webcontext初始化也失败,应用在挂起状态,但zkClient线程还是正常的;
  5. zookeeper服务器重启,zkClient开始重连,连接上zookeeper服务器;
  6. zkClient触发watch的一些代码,ClassLoader尝试加载org/apache/zookeeper/proto/SetWatches类,但是发现找不到类,于是抛出异常;
  7. zkClient捕获到异常,认为重连失败,close掉connection,休眠几秒之后,再次重连;
  8. 于是出现了zkClient反复重试连接zookeeper服务器,而且都是秒连秒断的情况。

总结一下: java.lang.NoClassDefFoundError: org/apache/zookeeper/proto/SetWatches的原因是由于应用程序没有正常启动,而zkClient线程在应用程序进程启动失败前已经正常启动了,所以导致zkClient没有在jvm中找到SetWatches该类。
由于下面两个问题太相似,所以我大胆猜测产生原因是相同的,于是去查机器上的java进程。ps -ef | grep java

java.lang.NoClassDefFoundError: org/apache/zookeeper/proto/ConnectRequest

java.lang.NoClassDefFoundError: org/apache/zookeeper/proto/SetWatches

果然,发现了在服务器上有三个相同应用程序进程:


 
  
也就是说,前面两个都是启动失败挂起状态。而最后一个是成功的,所以web服务能正常服务,但同样385或者
585也在不停往log日志中循环输出。这一定是某个粗心的同事干的好事。启动之前不知道先杀掉旧进程。
 
  
最后,解决办法:把385和585进程杀掉。kill -9 385 && kill -9 585
日志就没再打印了。