本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云
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 数据库,都可以大大缓解传统数据库在高并发下的不足;
应用架构优化
引入一些新的计算或者存储框架,利用新特性解决原有集群计算性能瓶颈等;或者引入分布式策略,在计算和存储进行水平化,包括提前计算预处理等,利用典型的空间换时间的做法等;都可以在一定程度上降低系统负载;
业务层面的优化
技术并不是提升系统性能的唯一手段,在很多出现性能问题的场景中,其实可以看到很大一部分都是因为特殊的业务场景引起的,如果能在业务上进行规避或者调整,其实往往是最有效的。
版权声明:本文为博主原创文章,未经博主允许不得转载。
最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!
本文原文出处:业余草: » Java性能调优常用方法