日常问题系列——借助Arthas解决noclassdeferror/nosuchmethoderror问题

自研软件平台对接华为fusioninsight,在公司测试环境中Parquet文件合并功能正常,现场环境失效。通过添加日志、捕获异常,发现noclassdeferror、nosuchmethoderror异常。利用grep查找相关类所在jar,借助阿里arthas工具确定加载类的jar包,找到问题所在。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

同一个对接华为fusioninsight平台的自研软件平台版本,在公司的测试环境中,合并parquet文件功能可以正常执行,但是某现场环境功能失效(其实是合并代码块没有运行)

解决问题过程

1、 通过添加逻辑执行日志的方式,判断合并代码是否执行到。结果发现parquet合并代码块没有执行到,但日志文件中确实没有抛出异常。
2、 parquet合并代码部分,显示抛出的只有IOException,因此代码中仅catch了IOException异常。后来想想又换成了Exception,不过还是日志里还是没有异常日志。最终一狠心,catch Throwable,终于,日志里出现了noclassdeferror、nosuchmethoderror异常。异常信息如下:

2019-04-23 17:32:17,931:INFO threadPool4MergeParquet-6 [com.sinovatio.shark.operator.common.MergeParquetTask:262] - {}
java.lang.NoClassDefFoundError: Could not initialize class org.apache.parquet.CorruptStatistics
	at org.apache.parquet.format.converter.ParquetMetadataConverter.fromParquetStatisticsInternal(ParquetMetadataConverter.java:347) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.format.converter.ParquetMetadataConverter.fromParquetStatjava.lang.NoClassDefFoundError: Could not initialize class org.apache.parquet.CorruptStatistics
	at org.apache.parquet.format.converter.ParquetMetadataConverter.fromParquetStatisticsInternal(ParquetMetadataConverter.java:347) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.format.converter.ParquetMetadataConverter.fromParquetStatistics(ParquetMetadataConverter.java:361) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.format.converter.ParquetMetadataConverter.fromParquetMetadata(ParquetMetadataConverter.java:817) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.format.converter.ParquetMetadataConverter.readParquetMetadata(ParquetMetadataConverter.java:794) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.hadoop.ParquetFileReader.readFooter(ParquetFileReader.java:484) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.hadoop.ParquetFileReader.<init>(ParquetFileReader.java:568) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.hadoop.ParquetFileReader.open(ParquetFileReader.java:492) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at com.sinovatio.shark.operator.common.MergeParquetTask.run(MergeSmallFilesOperator.scala:231) [shark-jetty.jar:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_162]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_162]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_162]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_162]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_162]
2019-04-23 17:32:17,931:INFO threadPool4MergeParquet-2 [com.sinovatio.shark.operator.common.MergeParquetTask:262] - {}
java.lang.NoSuchMethodError: org.apache.parquet.SemanticVersion.<init>(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
	at org.apache.parquet.CorruptStatistics.<clinit>(CorruptStatistics.java:45) ~[parquet-column-1.8.2.jar:1.8.1]
	at org.apache.parquet.format.converter.ParquetMetadataConverter.fromParquetStatisticsInternal(ParquetMetadataConverter.java:347) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.format.converter.ParquetMetadataConverter.fromParquetStatistics(ParquetMetadataConverter.java:361) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.format.converter.ParquetMetadataConistics(ParquetMetadataConverter.java:361) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.format.converter.ParquetMetadataConverter.fromParquetMetadata(ParquetMetadataConverter.java:817) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.format.converter.ParquetMetadataConverter.readParquetMetadata(ParquetMetadataConverter.java:794) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.hadoop.ParquetFileReader.readFooter(ParquetFileReader.java:484) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.hadoop.ParquetFileReader.<init>(ParquetFileReader.java:568) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at org.apache.parquet.hadoop.ParquetFileReader.open(ParquetFileReader.java:492) ~[parquet-hadoop-1.8.2.jar:1.8.2]
	at com.sinovatio.shark.operator.common.MergeParquetTask.run(MergeSmallFilesOperator.scala:231) [shark-jetty.jar:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_162]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_162]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_162]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_162]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_162]

3、 百度搜索noclassdeferror,没有提供什么解决方法,只是说运行期间,找不到该class。然后就将注意力转移到nosuchmethoderror异常。
4、 利用grep -R “org.apache.parquet.SemanticVersion”*,查找该类出现在哪些jar中,parquet-hadoop-bundle-1.8.1.jar和parquet-common-1.8.2.jar中均包含org.apache.parquet.SemanticVersion类。
5、 jinfo 进程号命令,查看进程加载了哪些jar(该步骤可不用)
6、 借助阿里arthas工具,查看进程中加载该类来自于哪个jar包;arthas使用方式如下:

  • java -jar arthas-boot.jar 显示了本机上所有的java进程
  • 输入java进程前面的序列号,并回车,进入交互命令行
  • sc -d org.apache.parquet.SemanticVersion,显示该类,来自于哪个jar。
    最终发现来自于parquet-hadoop-bundle-1.8.1.jar,该包中的org.apache.parquet.SemanticVersion类没有提供接受三个string参数的构造器,而parquet-common-1.8.2.jar包中提供了接受三个string参数的构造器。

解决方法

	将parquet-hadoop-bundle-1.8.1.jar升级为parquet-hadoop-bundle-1.8.2.jar,因为1.8.2中不再提供org.apache.parquet.SemanticVersion类,进程就直接去加载parquet-common-1.8.2.jar中的org.apache.parquet.SemanticVersion类。

遗留问题

同一套代码,lib包下的jar个数都一样,且parquet相关的jar版本也是一样的,公司测试环境为什么就可以执行成功?classloader加载lib的先后顺序(规则)如何?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值