k8s 上 Java 服务随机抛出 NoSuchMethodError 异场

2019-08-29 16:21:44 +08:00
 Ley

最近看了几天的问题,Google、文档后无果,来论坛上请教是否有人有解决思路。

我们使用 k8s host 某个 Java 项目,使用 jetty,项目通过 maven 管理依赖。之前一直正常,但最近遇到问题。 神奇的是,即使是同一份 image,每次 set 之后的表现也会不同。有时一切正常,有时则会在调用特定方法时抛出如下异常。 java.lang.NoSuchMethodError: com.google.common.base.Stopwatch.elapsed()Ljava/time/Duration;

这个问题看起来是项目中不同模块依赖不同的 guava 版本所致。一个我们依赖的第三方包需要依赖 22.0 版本的 guava,但其他一些依赖会找到比较老的版本。那些老版本缺少 elapsed() 方法。为此,我们在数月前曾经通过 shade 的 plugin 让依赖该包的项目始终使用 22.0 版本。一切相安无事。 最近两周,突然开始出现 mvn package 并 build 成 docker image 后放到 k8s 上,会随机发生上述异常。检查了编译结果,似乎和以前没有区别。至少,在需要依赖 22.0 版本的项目 jar 包中,guava 22.0 依然被 shade。 使用更新版本的 guava 似乎可以解决这个问题,但这显然掩盖了问题的根本原因。

有怀疑过 k8s 是否会缓存一些依赖,但看起来又不像,也查不到类似的文档。

不知诸位对这个问题有何高见?

7501 次点击
所在节点    Kubernetes
1 条回复
Ley
2019-09-29 20:52:27 +08:00
最后通过增加额外逻辑在 class loader 打印出 classpath 发现了问题所在。
原因是某个 Apache 的依赖内直接包装了老版本的 com.google.common.base.Stopwatch,因此在 mvn 的 dependency tree 中不会被列出。然后在 Jetty 的 embeded server 中 load class 时会在 mvn 中的版本和这个老版本中随机选择一个。如果选中了不包含 elapsed()Ljava/time/Duration 的版本,就会抛出异常。
由于该 Apache 依赖仅用于单元测试,将其 dependency scope 改为 test 便解决问题。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/596262

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX