V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Ley
V2EX  ›  Kubernetes

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

  •  
  •   Ley · 2019-08-29 16:21:44 +08:00 · 7458 次点击
    这是一个创建于 1673 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近看了几天的问题,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 是否会缓存一些依赖,但看起来又不像,也查不到类似的文档。

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

    1 条回复    2019-09-29 20:52:27 +08:00
    Ley
        1
    Ley  
    OP
       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 便解决问题。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5862 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 02:16 · PVG 10:16 · LAX 19:16 · JFK 22:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.