JAVA性能优化思路探究
1、背景
一个系统的上线除了常规的功能测试外,还需要经过严格的性能测试,达到预期的性能指标(一般包括响应时间、tps等),才能进入生产环境。
广义性能测试一般还包括负载测试(用于测试系统的容量:即在保证一定响应时间的情况下,系统允许多少并发用户访问)、压力测试(用于测试系统的稳定性)系统:即在保证一定的响应时间)一定压力下,检查测试系统的稳定性)、并发测试(即测试系统的多并发能力:即测试模拟多个用户访问同一个应用程序以发现并发问题,例如线程锁、资源竞争和数据库死锁等等。
通过性能测试,可以帮助我们尽快找到系统的瓶颈。如果您发现未达到预期的业务目标,则需要进行性能调整。性能调优的需求有时来自原型的验证,有时来自生产中的实际问题。不管是哪一种性能调优,我们一般都会遵循性能监控、性能分析、性能优化的步骤。以下部分提供了对每个步骤的详细分析。
2、性能监控
性能监控是性能调优的第一步。主要目的是了解系统当前运行状态、当前服务器资源使用情况、JVM内存使用情况、线程使用情况等,以便第一时间找到瓶颈点。
2.1 查看服务器配置
为了更好地评估服务器性能,首先应该了解当前托管服务器的配置。以下主要是针对linux服务器给出的常用查看命令。
2.1.1 CPU 配置
对于CPU来说,更关心的是CPU的逻辑核心总数,可以直接查看。
您可以使用 cat /proc/ 查看 CPU 的型号:
2.1.2 内存配置
使用free命令查看,可以看到总内存和使用情况
2.1.3 磁盘配置
使用 fdisk -l 查看所有磁盘配置,使用 df -TH 查看当前磁盘的目录挂载
有时需要确认当前磁盘是否为SSD盘,判断cat /sys/block/*/queue/的返回值(其中*为你的硬盘设备名称,如sda等) ,如果返回1,则表示磁盘可以旋转,则为HDD;否则,如果返回 0,则表示磁盘无法旋转,则可能是 SSD。如下图,sda是SSD盘。
2.1.4 网络配置
使用命令可以看到网卡的配置。有时候,需要查看当前网卡是1000M还是,可以通过查看速度来判断。如下图,eth4是千M网卡。
2.2 服务器监控
为了实时了解系统运行时的资源使用情况,我们需要对服务器的系统资源进行监控。下面列出常用命令和常用监控项。
2.2.1 CPU 监控
使用命令,2表示每2秒统计一次
专注于观察
Ø Procs中的r值,表示调度器运行队列的长度。如果该值长期大于 CPU 逻辑核数的 1 倍,则需要注意。如果超过3-4次,需要立即采取措施
Ø in(中断),cs(上下文切换),如果这两个值较大,说明系统内核消耗CPU较多
Ø 在Cpu一栏,如果us(用户态)的占比长期大于50%,则需要考虑优化算法。根据经验,us+sy比例的参考值为80%
您可以使用 -w -I -p pid 2 来监控应用程序的锁争用情况
让步上下文切换(cswch)占用时钟周期的3%到5%,说明Java应用面临锁竞争,抢占式上下文切换率()高,说明准备运行的线程数多于可用虚拟处理器的数量。
2.2.2 内存监控
也可以使用上面的查看内存页面交换,
重点关注free、si等栏目。如果free变小了,si等也在变化,说明内存不足。如果有磁盘交换的页面交换,则需要考虑增加内存。
2.2.3 网络监控
使用第三方软件,它提供了一个可视页面,您可以通过该页面实时监控网络流量。
2.2.4 个磁盘
用来监控
cpu属性值说明:
Ø 如果%的值太高,说明硬盘有I/O瓶颈。如果 %idle 的值很高,说明 CPU 比较空闲。如果 %idle 的值很高但系统响应很慢,可能是 CPU 正在等待分配内存。内存容量。如果%idle的值连续低于10,说明系统的CPU处理能力比较低,说明系统中最重要的资源是CPU。
磁盘属性值说明:
Ø 如果%util接近100%,说明I/O请求太多,I/O系统已经满载,磁盘可能出现瓶颈。如果svctm接近await,说明I/O几乎没有等待时间;如果await比svctm大很多,说明I/O队列太长,io响应太慢,需要进行必要的优化。如果avgqu-sz比较大,也意味着有等价的io等待。
2.3 JVM监控
使用jdk自带的工具在启动要连接的远程java进程时添加jmx配置,如下:
这样就可以通过ip+1111端口监听远程JVM了。
2.4 连接池监控
2.4.1 查看数据库连接池数量
使用 -an | grep 'db ip' | wc -l 命令,可以看到与数据库创建的连接池,并看到这个值与数据库连接池集合的最小值和最大值的关系。如果总是通过最大值,则需要考虑调整连接的最大值。
2.4.2 查看工作线程数
方法一:使用工具远程监控查看
方法二:使用命令查看
2.5 监控
2.5.1 查看配置
Ø 使用用户登录服务器(su - )
Ø 启动命令行模式(/as)
Ø 查看配置(显示sga;)
2.5.2 性能监控
Ø 使用命令行模式
Ø 开始时启动快照命令,停止时再次执行快速命令
备注:快照命令(exec TORY.();)
Ø 执行快照后,获取报告(@?/rdbms/admin/)
Ø 分析报告(关注前5次)
3 性能分析
3.1 JVM分析
3.1.1 堆分析
为了不影响在线的性能,可以使用heap dump,命令如下:
jmap -dump:live,=b,file=.
然后可以将生成的 .hprof 文件导入 mat 或进行分析,以查看哪些对象正在消耗内存。同时,软件提供的直方图方法可以快速方便地识别由于创建过多特定对象而导致的内存问题。
3.1.2 垃圾回收分析
JVM启动时,可以设置-、-XX:等参数开启gc日志收集。您还可以使用 jstat 进行监控和分析。例如,jstat-pid 2 用于每 2 秒打印一次当前 Java 堆和 GC 状态。
3.1.3 线程分析
使用jdk自带的jmc和工具,可以查看阻塞线程。JMC 中集成的 JFR 可以轻松检索导致线程阻塞的事件。并且在一定程度上可以检查线程阻塞在哪些资源上。定位思路如下:
4 性能优化
在对系统进行深度优化之前,首先要找出CPU使用率低的原因。优化代码的目的是在更短的时间内增加而不是减少 CPU 使用率。
4.1 JVM启动参数优化
4.1.1 本机内存优化
原生内存的优化,包括使用压缩OOP(jvm启动参数加-XX:+)和调整大内存分页(修改linux配置和jvm启动参数-XX:)等,可以提高性能。
4.1.2 垃圾回收机制的优化
Ø 合理设置堆的大小,合理设置分代空间的划分:设置太小,容易GC频繁,设置太大,GC暂停时间太长。同时,为了避免可能使用虚拟内存,内存页面交换导致速度变慢,至少要预留1G的物理内存。
Ø 如何选择每个分区的大小要根据应用中对象生命周期的分布情况:如果应用有大量的短期对象,应该选择更大的年轻代;如果持久化对象比较多,老年代应该适当增加。
Ø 稳定振荡的堆大小:使-Xms和-Xmx的大小相同,有利于垃圾回收。
4.1.3 大对象分配优化
Ø 大对象尽量分配在TLAB中。如果大量对象出现在 TLAB 之外,则需要考虑调整 TLAB 参数,或者减小分配对象的大小。可以使用 -XX: 标志查看结果。
Ø 将大对象分配给老年代:将大对象直接分配给老年代,维护新生代对象的结构完整性提高GC效率,通过-XX:ld设置进入老年代的阈值。
4.2 java编程优化
因为在实际编程中,性能优化涉及的点很多,以下只是一些常见的优化项,供参考。
4.2.1 线程池优化
Ø 根据当前服务器CPU数,合理设置最大线程数、最小线程数、线程池任务队列大小。对于 CPU 密集型任务,尽量少配置线程,比如配置一个 Ncpu+1 线程的线程池。对于IO密集型任务,由于线程并不总是在执行任务,所以尽量配置多线程,比如2*Ncpu。
Ø 推荐使用有界队列,可以增加系统的稳定性和预警能力。
Ø 不同优先级的任务可以使用优先级队列进行处理。
Ø 执行时间不同的任务可以交给不同大小的线程池处理,也可以使用优先队列让执行时间短的任务先执行。设置线程的优先级。
4.2.2 其他编程细节
Ø 最小化内存使用,减小对象大小,设置类型时考虑最小化原则,移除未使用的属性,以及未使用的实例变量。
Ø 通过使用对象池和线程局部变量来增强对象复制。对象复用和GC有点矛盾,所以主要考虑对象初始化的成本比较高(也就是初始化时间比较长)。
Ø 对于保存同步对象的对象,实际上并不需要在多个线程之间共享,而且还要在不同的现实中传输对象,考虑使用线程局部变量来减少同步竞争。
Ø 在某些场景下,优化使用java8并行流的方式
4.3 数据库优化
4.3.1 使用预编译
使用该方法,复用 pool可以大大提升性能,同时避免大量大对象池化带来的GC问题。
4.3.2 使用连接池
引入连接池并在启动时进行配置
Ø 创建连接的成本非常高。通过JDBC连接池获取连接可以节省创建连接的时间。同时,需要合理设置连接池的大小。
Ø 合理设置:例如设置检索时的batch值,设置最优预取值,设置batch值可以提高检索的性能。
Ø 事务优化:事务的提交以及与事务相关的锁机制会影响系统的性能。需要考虑事务隔离级别的合理设置和批量提交的策略。
5 性能实践经验总结
5.1 清除并发性能没有提升
5.1.1 问题症状
在使用java8的并行流计算时,发现并发性能上不去,随着时间的推移性能会不断下降。
5.1.2个优化点
Ø 引入连接池,将单笔延迟降低到5ms
Ø 关闭日志
Ø 将sql改为预编译模式
Ø 提升服务器内存
5.2 夏尔和中泰之间有很多联系
5.3 可以随意配置吗?
6 总结
6.1 性能工具箱
6.1.1 压力测量工具
Jmter 是一个开源的压力测量工具,也很容易使用。它的使用就不介绍了,但是这里有一些需要注意的地方:
Ø 它的实时绘制依赖于服务器的响应。如果压测仪和服务器时间不同步,会出现显示图故障现象。为了获得更准确的性能曲线,建议使用命令行方式。
Ø 有时发现压测性能不上去,可能原因在客户端。主要考虑:客户端的CPU不足以支持所需的客户端线程数,或者客户端在发送请求之前需要花费大量时间来处理响应。
6.1.2 JVM相关
除了上面提到的jdk自带的工具外,还有IBM提供的,商业软件也很强大。
6.1.3 数据库相关
对于数据库性能监控,可以使用,基于mysql的不同版本都支持。
6.1.4 网络相关
Linux自带的命令常用来导出抓包,然后用来分析,非常强大。
本文主要总结了java性能调优的大致思路,并分享了一些常用的性能优化最佳实践。我希望每个人都必须提供帮助。
从:
郑重声明:本文版权归原作者所有,转载文章仅出于传播更多信息之目的。如作者信息标注有误,请尽快联系我们修改或删除,谢谢。