Java性能调优常用方法
Java给大部分人的感觉就是慢,有严重的性能问题。其实程序慢的问题,与语言无关,与Java无关。Java应用的性能优化也是一个老生常谈的话题,但是只要我们深入的了解性能调优方法,走遍天下都不怕!
根据我的个人经验,将Java性能优化分为4个层级:应用层、数据库层、框架层、JVM 层。通过介绍Java性能诊断工具和思路,总结出性能优化案例以供参考。
Java性能优化分层模型
根据我的分层,应用层、数据库层、框架层、JVM 层四个层,每层优化难度逐级增加,涉及的知识和解决的问题也会不同。比如应用层需要理解代码逻辑,通过Java线程栈定位有问题代码行等;数据库层面需要分析 SQL、定位死锁等;框架层需要懂源代码,理解框架机制;JVM 层需要对 GC 的类型和工作机制有深入了解,对各种 JVM 参数作用了然于胸。围绕Java性能优化,有两种最基本的分析方法:现场分析法和事后分析法。现场分析法通过保留现场,再采用诊断工具分析定位。现场分析对线上影响较大,部分场景(特别是涉及到用户关键的在线业务时)不太合适。事后分析法需要尽可能多收集现场数据,然后立即恢复服务,同时针对收集的现场数据进行事后分析和复现。
性能诊断工具
性能诊断一种是针对已经确定有性能问题的系统和代码进行诊断,还有一种是对预上线系统提前性能测试,确定性能是否符合上线要求。可以用各种性能压测工具(例如JMeter)进行测试。针对Java应用,性能诊断工具主要分为两层:OS层面和Java应用层面(包括应用代码诊断和GC诊断)。OS层面的诊断主要关注的是 CPU、Memory、I/O 三个方面。CPU诊断是对于CPU主要关注平均负载(Load Average),CPU使用率,上下文切换次数(Context Switch)。另外也可以通过top命令可以查看系统平均负载和CPU使用率。
vmstat命令
一般使用vmstat命令可以查看CPU的上下文切换次数,例如在linux环境下,输入“vmstat 1”,结果如下图:
上下文切换次数发生的场景主要有如下几种:
时间片用完,CPU 正常调度下一个任务;
被其它优先级更高的任务抢占;
执行任务碰到 I/O 阻塞,挂起当前任务,切换到下一个任务;
用户代码主动挂起当前任务让出 CPU;
多任务抢占资源,由于没有抢到被挂起;
硬件中断。
Java 线程上下文切换主要来自共享资源的竞争。一般单个对象加锁很少成为系统瓶颈,除非锁粒度过大。但在一个访问频度高,对多个对象连续加锁的代码块中就可能出现大量上下文切换,成为系统瓶颈。
内存方面(Memory)
从操作系统角度,内存关注应用进程是否足够,可以使用 free –m命令查看内存的使用情况。通过top命令可以查看进程使用的虚拟内存VIRT和物理内存RES,根据公式VIRT = SWAP + RES可以推算出具体应用使用的交换分区(Swap)情况,使用交换分区过大会影响Java应用性能,可以将swappiness值调到尽可能小。因为对于Java应用来说,占用太多交换分区可能会影响性能,毕竟磁盘性能比内存慢太多。
I/O方面
I/O包括磁盘I/O和网络I/O,一般情况下磁盘更容易出现I/O瓶颈。通过iostat可以查看磁盘的读写情况,通过CPU的I/O wait可以看出磁盘I/O是否正常。如果磁盘I/O一直处于很高的状态,说明磁盘太慢或故障,成为了性能瓶颈,需要进行应用优化或者磁盘更换。
除了常用的top、ps、vmstat、iostat等命令,还有其他Linux工具可以诊断系统问题,如mpstat、tcpdump、netstat、pidstat、sar等。下面摘录了部分Linux系统不同设备类型的性能诊断工具。
总结与建议
性能调优同样遵循 2-8 原则,80%的性能问题是由 20%的代码产生的,因此优化关键代码事半功倍。同时,对性能的优化要做到按需优化,过度优化可能引入更多问题。对于 Java 性能优化,不仅要理解系统架构、应用代码,同样需要关注 JVM 层甚至操作系统底层。总结起来主要可以从以下几点进行考虑:
基础性能的调优
这里的基础性能指的是硬件层级或者操作系统层级的升级优化,比如网络调优,操作系统版本升级,硬件设备优化等。比如 F5 的使用和 SDD 硬盘的引入,包括新版本 Linux 在 NIO 方面的升级,都可以极大的促进应用的性能提升;
数据库性能优化
包括常见的事务拆分,索引调优,SQL 优化,NoSQL 引入等,比如在事务拆分时引入异步化处理,最终达到一致性等做法的引入,包括在针对具体场景引入的各类 NoSQL 数据库,都可以大大缓解传统数据库在高并发下的不足;
应用架构优化
引入一些新的计算或者存储框架,利用新特性解决原有集群计算性能瓶颈等;或者引入分布式策略,在计算和存储进行水平化,包括提前计算预处理等,利用典型的空间换时间的做法等;都可以在一定程度上降低系统负载;
业务层面的优化
技术并不是提升系统性能的唯一手段,在很多出现性能问题的场景中,其实可以看到很大一部分都是因为特殊的业务场景引起的,如果能在业务上进行规避或者调整,其实往往是最有效的。
如果想学习Java工程化、高性能及分布式、深入浅出。性能调优、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级架构进阶群:180705916,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家