JFR 实战之一

自从2016年左右开始干SRE, 就了解到 JFR 是一个非常有用的工具, 尤其在性能调优这一块. 在好几本书和一些文章中都有人提及过, 但是很少见有人用它来解决实际的问题. 可能的原因包括: JFR的很多事件都是JVM本身暴露的稍底层的一些时间, 不熟悉JVM运行机制的话, 很难从这边比较容易的看出问题. JFR 如果用在生产环境是需要付费的.

为了从理论到实践, 这里就在本地开发环境打开JFR, 然后收集一些数据, 然后解读.

设置环境, 开启JFR

本地正好有个 Java 应用: Pycharm, 通过下面的命令可以看到它的一些启动参数:

$ jcmd
60759 jdk.jcmd/sun.tools.jcmd.JCmd
22348 com.intellij.idea.Main

$ jcmd 22348 VM.command_line

$ jcmd 22348 VM.flags -all | grep FlightRecorder
     bool FlightRecorder                           = false                                     {product} {default}
    ccstr FlightRecorderOptions                    =                                           {product} {default}

我们修改 Pycharm 的 JVM 参数. 从 Pycharm 菜单依次点击: Help -> Edit Custom VM Options. 就打开了 ~/Library/Application\ Support/JetBrains/PyCharmCE2023.3/pycharm.vmoptions. 添加下面选项:

-XX:+UnlockCommercialFeatures
-XX:+FlightRecorder

上面的修改类似于 java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder MyApp

重启 Pycharm, 我们再次检查它的参数:

jcmd 62236 VM.flags -all | grep FlightRecorder
     bool FlightRecorder                           = true                                      {product} {command line}
    ccstr FlightRecorderOptions                    =                                           {product} {default}

收集数据

上面的-XX:+FlightRecorder 选项只是说明我们打开了 JFR 的开关, 真正的收集事件并未开始. 通常我们可以通过 jcmd 命令行或者一些GUI工具(JConsole, Java Mission Control等)来开始收集.

通过运行 jcmd 命令, 我们可以看到有关 JFR 的一些命令, 然后通过 help 能看到对应子命令的更多内容:

$ jcmd <pid> help | grep JFR
JFR.check
JFR.configure
JFR.dump
JFR.start
JFR.stop

$ jcmd 62236 help JFR.start
   ... 可以看到很多参数省略 ...

通过如下的命令, 我们可以启动收集:

$ jcmd 62236 JFR.start name=sample1,filename=/tmp/sample1.jfr,during=1m
62236:
Started recording 1. No limit specified, using maxsize=250MB as default.

Use jcmd 62236 JFR.dump name=sample1,filename=/tmp/sample1.jfr,during=1m filename=FILEPATH to copy recording data to file.

查看这个收集任务 并把数据保存到文件

$ jcmd 62236 JFR.check
62236:
Recording 1: name=sample1,filename=/tmp/sample1.jfr,during=1m maxsize=250.0MB (running)

jcmd 62236 JFR.dump name=sample1,filename=/tmp/sample1.jfr,during=1m filename=/tmp/sample1.jfr
62236:
Dumped recording "sample1,filename=/tmp/sample1.jfr,during=1m", 6.2 MB written to:

/private/tmp/sample1.jfr

关于这几个子命令的更多信息: https://docs.oracle.com/javacomponents/jmc-5-4/jfr-runtime-guide/comline.htm#JFRUH188

解读数据

解读数据需要 Java Mission Control (JMC), 下载页面: https://www.oracle.com/java/technologies/javase/products-jmc8-downloads.html

启动 JMC, 然后打开刚才的文件.
jmc.png

事件类型

JFR 收集3类数据类型:

  1. 持续事件: 需要一段时间才会发生,并在完成时记录。你可以设置持续事件的阈值,以便只记录持续时间超过指定时间段的事件。
  2. 瞬时事件: 立即发生,并立即记录。
  3. 样本事件: 以固定间隔记录,以提供系统活动的样本。你可以配置采样发生的频率。

标签: none

仅有一条评论

  1. Peter Peter

    你是最棒的SRE

添加新评论