关于后端:如何在OpenJ9场景下使用Arthas

12次阅读

共计 4521 个字符,预计需要花费 12 分钟才能阅读完成。

Alibaba 开源的 Arthas 是一个十分有名的 Java 诊断工具,他能够解析 JVM 的运行资源占用,运行状况,能够查看类的加载过程,应用的类加载器等等。然而比拟惋惜的是,他没有对于 OpenJ9 做出额定的反对,因而当你的 JVM 抉择 OpenJ9 后,应用 arthas 可能会存在肯定问题。本文将从我的亲自应用登程,看看 OpenJ9 在应用 Arthas 时会遇到哪些问题?

dashboard

dashboard 是 arthas 的指令之一,该指令用于展现以后零碎的实时面板。然而在理论应用中会发现,如果 OpenJ9 中启用 -Xgcpolicy:balanced 的 gc 策略,会报如下的谬误:

[arthas@73192]$ dashboard
process dashboard failed: init argument cannot be less than -1

查看 Arthas 的日志文件,文件中有更加具体的日志:

java.lang.IllegalArgumentException: init argument cannot be less than -1
        at java.lang.management.MemoryUsage.<init>(MemoryUsage.java:94)
        at com.ibm.java.lang.management.internal.MemoryPoolMXBeanImpl.getUsageImpl(Native Method)
        at com.ibm.java.lang.management.internal.MemoryPoolMXBeanImpl.getUsage(MemoryPoolMXBeanImpl.java:235)
        at com.taobao.arthas.core.command.monitor200.MemoryCommand.getUsage(MemoryCommand.java:82)
        at com.taobao.arthas.core.command.monitor200.MemoryCommand.memoryInfo(MemoryCommand.java:52)
        at com.taobao.arthas.core.command.monitor200.DashboardCommand$DashboardTimerTask.run(DashboardCommand.java:245)
        at java.util.TimerThread.mainLoop(Timer.java:555)
        at java.util.TimerThread.run(Timer.java:505)

原本认为是 Arthas 对于 OpenJ9 不兼容导致的,然而通过一番钻研发现事件并不是那么简略。

写一个最简略的程序来进行验证:

public static void main(String[] args) {List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();

    for (MemoryPoolMXBean memoryPoolMXBean : memoryPoolMXBeans) {memoryPoolMXBean.getUsage();
    }
}

这么简略一个 demo 竟然在 OpenJ9 balanced gc 策略下抛出了异样:

Exception in thread "main" java.lang.IllegalArgumentException: init argument cannot be less than -1
    at java.management/java.lang.management.MemoryUsage.<init>(MemoryUsage.java:94)
    at java.management/com.ibm.java.lang.management.internal.MemoryPoolMXBeanImpl.getUsageImpl(Native Method)
    at java.management/com.ibm.java.lang.management.internal.MemoryPoolMXBeanImpl.getUsage(MemoryPoolMXBeanImpl.java:235)
    at org.example.openj9.Test.main(Test.java:12)

通过测试验证,确认了这个是 OpenJ9 的 bug,错怪 Arthas 了!

通过和 OpenJ9 社区的沟通,发现这个 bug 会在闲暇的 region 数小于 Eden region 数时产生,此时的 ”reserved size” 会小于 0,并导致报错。遗憾的是,此 bug 目前还未修复,预计将在后续的 7 月份的版本中进行修复并公布。

trace

应用 trace 能够排查具体的类的加载时长,排查执行慢的起因。不过在 OpenJ9 场景下应用 trace 会呈现如下报错:

[arthas@22508]$ trace org.springframework* * '#cost > 1000'
Affect(class count: 4180 , method count: 33388) cost in 28438 ms, listenerId: 1
Enhance error! exception: java.lang.VerifyError
error happens when enhancing class: null, check arthas log: /Users/logs/arthas/arthas.log

查看日志发现如下报错:

java.lang.VerifyError: null
        at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
        at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:156)
        at com.taobao.arthas.core.advisor.Enhancer.enhance(Enhancer.java:446)
        at com.taobao.arthas.core.command.monitor200.EnhancerCommand.enhance(EnhancerCommand.java:162)
        at com.taobao.arthas.core.command.monitor200.EnhancerCommand.process(EnhancerCommand.java:109)
        at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
        at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
        at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)
        at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)
        at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:826)

这让我百思不得其解,没方法只好求助 Arthas 社区,可是失去的后果就是 Arthas 不反对 OpenJ9。没方法,既然不反对,那么咱们就换种方法来排查问题。

火焰图

Arthas 火焰图是基于开源我的项目 async-profiler 实现的,async-profiler应用 C ++ 实现。反对生成利用热点的火焰图。其也能够用于排查利用执行慢的问题。他实质上是通过一直的采样,而后把收集到的采样后果生成火焰图。

然而在理论的应用中,会发现火焰图也不反对 OpenJ9。

没方法,又又又只能去社区寻找答案。最终通过排查,发现 async-profiler 是做了 OpenJ9 的反对的,不过,这些反对在 2.7+ 版本后才陆续合并入主分支,而 Arthas 的最新版本援用的是 2.6.x 的async-profiler,因而不反对 OpenJ9 也是情理之中了。

于是咱们只好本人入手饥寒交迫。好在 Arthas 集成 async-profiler 的办法十分粗犷,是间接应用的 so 文件,于是咱们间接替换 Arthas 的 async-profiler 目录下的几个 so 文件,将之替换为最新版本的,果然火焰图能力就可能失常应用了。

后续在提了 Issue 之后,Arthas 社区近期反馈曾经将 async-profiler 降级至了高版本,因而只有下载最新版本就能让 OpenJ9 也能够应用 Arthas 的火焰图能力了。

总结

OpenJ9尽管有其劣势,然而在理论中的用户远远不如 HotSpot,因而在各个开源我的项目中的反对还远远不够。在折腾 Arthas 的过程中遇到了有数的坑,而且很多还是无奈简略解决的,本文只是简略选取几个遇到的典型问题,心愿可能有雷同需要的敌人们可能一起来 踩坑 摸索。

正文完
 0