何为精细化?

我们常说“精细化运营”、“精细化管理”,那什么是“精细化性能剖析”呢?在回答这个问题之前,我们先看看我们这个行业开发人员饱受的困扰:

  • 不清楚应用的运行情况,包括但不限于GC情况、热点代码、热点线程、异常(特别是被吞没的异常);
  • 不清楚应用代码执行情况,甚至不知道某个模块是否还可能会运行,尤其是对于有着一定历史的应用,可能已经有很多开发在上面贡献过代码,但随着业务发展这些功能可能已经不再被使用;
  • 不清楚应用的IO情况,注意,这里说的绝对不仅仅是zabbix上的"磁盘IO",而是具体到某个文件、某个端口、某个线程的IO情况;

这些问题导致的直接后果就是:对于性能优化,无从下手,只能凭经验和直觉去猜测、埋点、优化,当然,最终结果一般就是“加机器扩容”。

了解了我们锁遇到的困扰或者面临的困境之后,我们结合精细化运营和精细化管理的概念来回答什么精细化性能剖析。精细化是基于规范化的基础上建立的一种理念,我们要把目标粒度细致化、精准化、具体化。精细化性能剖析,是基于某种规范详细的分析应用的性能,能够量化性能指标,明确出问题的瓶颈。

值得高兴的是JDK7以上已经内置了一款新型的性能剖析工具,也就是今天要重点介绍的-Java Flight Recorder,简称JFR,可以类比为飞机上的黑匣子。

JFR究竟是什么?

Java Flight Recorder(JFR)本来是一个商业特性,不过现在也可以直接用。

JFR 记录了关于 Java 运行时及运行在其内的 Java 应用程序的详细信息,记录用少量的开销完成。数据是作为时间上的数据点(称为事件)记录的。典型的事件可以是线程等待锁、GC、CPU 周期使用数据等。

在创建飞行记录时,可以选择哪些事件应当保存,这叫做记录模板。有些模板只保存基本事件,对性能几乎没有影响。其他模板可能有轻微的性能开销,还可能触发 GC 来收集更多信息。通常,超过百分之几的开销是很罕见。飞行记录可用于调试很大范围的问题,从性能问题到内存泄漏或严重的锁竞争。

注意,JFR是一个性能数据采集工具,它把最终采集到的数据存在一个格式为jfr的文件中,由于本身并不具备数据分析或者可视化功能,所以一般我们需要配合JDK另外一个内置工具,即JMC一起使用。

JMC又是什么?

它是在 JAVA 7u40 发布中加入的图形化性能监控工具,它可以直接打开由jfr生成的原始数据采集文件,

请在自己机器的命令行输入 jmc 来体验。

相比其它Profile工具比有什么优点?
在开发环境中,我们用VisualVM、JProfiler等,功能强大,支持图形化界面操作,可以很快定位代码问题。

但是他们对应用性能的影响也非常大,所以不适合在生产环境下使用。还有这些软件要attach到jvm进程上,生产环境一般网络隔离,很难做到。

在生产环境我们最常用的profiling工具就是java/bin下的jstack,多做几次jstack,也相当于profiling了。

jstack方便易用,但并不是特别适合来做profiling,操作频率低,会导致safepoint指标急剧增长等等。

重点来了,使用jfr不需要在现有应用上额外添加任何参数、重启进程等,直接在命令行执行即可实时生效,100%无入侵,稳定可靠不影响线上应用运行。

安全性如何?

我们很多应用涉及用户敏感数据,所以安全性是我们最为关注的红线之一

由于这个工具可以直接在线上使用,那么它会有安全性问题吗?会造成客户数据泄露吗?

答案是否定的,因为jfr采集的性能数据其实可以看作是JVM本身的元数据而不是业务数据,因此不存在数据泄漏问题,可以放心使用。那么,JFR该如何使用?很简单,按照下面三个步骤操作;

  • 选定一台机器,登录上去,并找到要监控的进程PID

  • 执行下列命令

    pid=`jcmd | grep java进程关键词 | awk '{print $1}'`
    jcmd $pid VM.unlock_commercial_features #先解锁技能
    jcmd $pid JFR.start name=myrec settings=profile delay=20s duration=2m filename=/tmp/$pid.jfr
    #其中,delay参数表示profile延迟启动时间,duration表示持续采集时间,这里设置为2分钟
    #settings表示使用哪种采集配置
    #官方默认自带一个名为profile的配置,这个配置不会收集异常信息
    #注意,采集数据生成后请执行下列命令移除这个采集
    jcmd $pid JFR.stop name=myrec
    
    
    
  • 这样就好了,等待2分钟+20秒,/tmp/pid.jfr文件就生成好了,这个文件直接导入JMC工具即可

如何定制采集信息

默认采集配置收集的信息较少,性能较好,若需要收集更多信息,请使用JMC工具的模版管理器来进行自定义,

生成好的自定义文件放置在<JDK_HOME>/jre/lib/jfr目录下即可

JMC信息

下面以线上某个核心应用某台机器为例

上图是该应用2分钟内抛出的异常信息(包括代码中被默默吃掉的),众所周知,Java的异常比较消耗性能,所以我们要尽量减少这些发生的概率。

上图是热点线程和该线程的热点方法,当然这个是要看具体业务场景来分析和优化。

上图是IO情况,由于该应用没有文件io,因此只截取了网络IO部分,可以很清晰的看出网络连接和具体交互情况。