了解问题
服务是突然变慢还是长时间运行后观察到变慢?类似问题是否重复出现?“慢”的定义是什么?
理清问题的症状,定位具体的原因
- 问题可能来自于 Java 服务自身,也可能仅仅是受系统里其他服务的影响。初始判断可以先确认是否出现了意外的程序错误,例如检查应用本身的错误日志。如果没有,可以先检查系统级别的资源等情况,监控 CPU、内存等资源是否被其他进程大量占用,并且这种占用是否不符合系统正常运行状况。
- 监控 Java 服务自身,例如 GC 日志里面是否观察到 Full GC 等恶劣情况出现,或者是否 Minor GC 在变长等;利用 jstat 等工具,获取内存使用的统计信息;利用 jstack 等工具检查是否出现死锁等。
- 定位了程序错误或者 JVM 配置的问题后,就可以采取相应的补救措施,然后验证是否解决,否则还需要重复上面部分过程。
性能分析方法论
- 自上而下。从应用的顶层,逐步深入到具体的不同模块,或者更近一步的技术细节单元,找到可能的问题和解决办法。这是最常见的性能分析思路,也是大多数工程师的选择。
- 自下而上。从类似 CPU 这种硬件底层,判断类似 Cache-Miss 之类的问题和调优机会,出发点是指令级别优化。这往往是专业的性能工程师才能掌握的技能,并且需要专业工具配合,大多数是移植到新的平台上,或需要提供极致性能时才会进行。
自上而下分析
系统性能分析中,CPU、内存和 IO 是主要关注项。
CPU
1.对于 CPU,如果是常见的 Linux,可以先用 top 命令查看负载状况。
可以看到,其平均负载(load average)的三个值(分别是 1 分钟、5 分钟、15 分钟)非常低,并且暂时看并没有升高迹象。如果这些数值非常高(例如,超过 50%、60%),并且短期平均值高于长期平均值,则表明负载很重;如果还有升高的趋势,那么就要非常警惕了。
1)1分钟Load>5,5分钟Load<1,15分钟Load<1:短期内繁忙,中长期空闲,初步判断是一个“抖动”,或者是“拥塞前兆”
2)1分钟Load>5,5分钟Load>1,15分钟Load<1:短期内繁忙,中期内紧张,很可能是一个“拥塞的开始”
3)1分钟Load>5,5分钟Load>5,15分钟Load>5:短中长期都繁忙,系统“正在拥塞”
4)1分钟Load<1,5分钟Load>1,15分钟Load>5:短期内空闲,中长期繁忙,不用紧张,系统“拥塞正在好转”
2.利用 top 命令【如:top -Hp pid】获取相应 pid,“-H”代表 thread 模式,找到最耗费 CPU 的 Java 线程。
3.利用 vmstat 之类,查看上下文切换的数量,比如下面就是指定时间间隔为 1,收集 10 次。
vmstat -1 -10
如果每秒上下文(cs,context switch)切换很高,并且比系统中断高很多(in,system interrupt),就表明很有可能是因为不合理的多线程调度所导致。当然还需要利用 pidstat 等手段,进行更加具体的定位。
除了 CPU,内存和 IO 是重要的注意事项,比如:
- 利用 free 之类查看内存使用。
- 或者,进一步判断 swap 使用情况,top 命令输出中 Virt 作为虚拟内存使用量,就是物理内存(Res)和 swap 求和,所以可以反推 swap 使用。显然,JVM 是不希望发生大量的 swap 使用的。
- 对于 IO 问题,既可能发生在磁盘 IO,也可能是网络 IO。例如,利用 iostat 等命令有助于判断磁盘的健康状况。如果 IO 表现较差,拖累了整体性能,解决办法就是申请替换了机器。
JVM 层面的性能分析
- 利用 JMC、JConsole 等工具进行运行时监控。
- 利用各种工具,在运行时进行堆转储分析,或者获取各种角度的统计数据(如 jstat -gcutil 分析 GC、内存分带等)。
- GC 日志等手段,诊断 Full GC、Minor GC,或者引用堆积等。