热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JAVA性能优化思路探究

1、背景介绍一个系统的上线除了常规的功能性测试外,还需要经过严格的性能测试,满足预期的性能指标(常见的有响应时间,tps等),才允许上生产环境。广义的性能

1、背景介绍

一个系统的上线除了常规的功能性测试外,还需要经过严格的性能测试,满足预期的性能指标(常见的有响应时间,tps等),才允许上生产环境。

广义的性能测试一般还包含负载测试(用于测试系统的容量:即系统在保证一定响应时间的情况下能够允许多少并发用户的访问),压力测试(用于测试系统的稳定性:即在保证一定压力的情况下,查看测试系统的稳定性),并发测试(即测试系统多并发能力:即模拟多用户访问同一应用的测试,用于发现并发问题,比如线程锁,资源竞争,数据库死锁等)等。

通过性能测试,可以帮助我们尽快发现系统的瓶颈。如果发现未能满足预期的业务目标,则需要进行性能调优。性能调优的需求,有时候来自于原型的验证,有时候来自于生产上实际的问题,不管哪一类的性能调优,我们一般按照性能监控,性能分析,性能优化这几个步骤进行。以下章节会对每个步骤进行详细分析。

2、性能监控

性能监控是性能调优的第一步,主要目的在于了解当前系统运行的状态,了解当前服务器资源使用情况,JVM的内存使用,线程使用等情况,以便于第一时间找到瓶颈点。

2.1 查看服务器配置

为了更好评估服务器性能,首先应了解当前宿主服务器的配置情况。以下主要是针对linux服务器给出的常见的查看命令。

2.1.1 CPU配置

对于CPU,比较关心的是CPU的总逻辑核数,可以直接使用mpstat查看。

JAVA性能优化思路探究

可以使用cat /proc/cpuinfo查看CPU的型号:

JAVA性能优化思路探究

2.1.2 内存配置

使用free命令进行查看,可以看到总的内存,以及使用的情况

JAVA性能优化思路探究

2.1.3 磁盘配置

使用fdisk -l可以查看到所有的磁盘配置情况,使用df -TH可以看到当前磁盘的目录挂载情况

JAVA性能优化思路探究

有时候,需要确认当前磁盘是否为SSD盘,判断cat /sys/block//queue/rotational的返回值(其中为你的硬盘设备名称,例如sda等等),如果返回1则表示磁盘可旋转,那么就是HDD了;反之,如果返回0,则表示磁盘不可以旋转,那么就有可能是SSD了。如下图所示,sda是SSD盘。

JAVA性能优化思路探究

2.1.4 网络配置

使用ifconfig命令,可以看到网卡的配置情况。有时候,需要查看当前网卡是千M还是万M,可以通过ethtool查看speed可以判断。如下图所示,eth4是千M网卡。

JAVA性能优化思路探究
JAVA性能优化思路探究

2.2 服务器监控

为了能实时了解系统运行时,资源的占用情况,我们就需要对服务器的系统资源进行监控,以下列出常见的命令以及常用的监控事项。

2.2.1 CPU监控

使用vmstat命令,vmstat 2代表每2秒统计一次

JAVA性能优化思路探究

重点观察

Ø Procs中r值,它代表调度程序运行队列的长度,如果该值长时间大于CPU逻辑核数1倍以上,需要关注,超过3-4倍需要马上采取行动

Ø System中in(中断),cs(上下文切换)如果两值较大,说明系统内核消耗CPU较多

Ø Cpu列中,如果us(用户态)占比长期大于50%时,就需要考虑优化算法。根据经验us+sy占比参考值为80%

可以使用pidstat -w -I -p pid 2,监控应用的锁竞争情况

JAVA性能优化思路探究

让步式上下文切换(cswch)时钟周期占用3% ~ 5%,说明Java应用面临锁竞争,抢占式上下文切换率(nvcswch)高,说明预备运行的线程数多于可用的虚拟处理器数。

2.2.2 内存监控

也可以使用上述的vmstat查看内存页面交换,

JAVA性能优化思路探究

重点观察free,si,so这几列,如果free变小,而且si,so在变化,说明存在内存不足,跟磁盘swap,有发生页面交换的情况,需要考虑加大内存。

2.2.3 网络监控

使用第三方软件iptraf,它提供了可视化的页面,通过它可以实时监控网络流量情况。

JAVA性能优化思路探究

2.2.4 磁盘

使用iostat进行监控

JAVA性能优化思路探究

cpu属性值说明:

Ø 如果%iowait的值过高,表示硬盘存在I/O瓶颈,%idle值高,表示CPU较空闲,如果%idle值高但系统响应慢时,有可能是CPU等待分配内存,此时应加大内存容量。%idle值如果持续低于10,那么系统的CPU处理能力相对较低,表明系统中最需要解决的资源是CPU。

disk属性值说明:

Ø 如果%util接近100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘可能存在瓶颈。如果svctm比较接近await,说明I/O几乎没有等待时间;如果await远大于svctm,说明I/O队列太长,io响应太慢,则需要进行必要优化。如果avgqu-sz比较大,也表示有当量io在等待。

2.3 JVM监控

使用jdk中自带的jvisualvm工具,在要连接的远程java进程,启动时增加jmx的配置,如下:

JAVA性能优化思路探究

这样jvisualvm就可以通过ip+1111端口侦听远程JVM的情况了。

2.4 连接池监控

2.4.1 查看数据库连接池数量

使用netstat –an | grep ‘db ip’ | wc –l命令,可以看到与数据库创建的连接池,看这个值跟设置的数据库连接池的最小值,以及最大值的关系。如果始终通过最大值,需要考虑调整连接的最大值。

2.4.2 查看工作线程数

方法1:使用jvisualvm工具远程监控来查看

方法2:使用命令查看

2.5 Oracle监控

2.5.1 查看oracle配置

Ø 使用oracle的用户登录oracle的服务器(su – oracle)

Ø 启动sqlplus命令行模式(sqlplus / as sysdba)

Ø 查看配置(Show parameter sga;)

2.5.2 性能监控

Ø 使用sqlplus命令行模式

Ø 开始时启动快照命令,停止时再执行一遍快速命令

备注:快照命令(exec
DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT();)

Ø 快照执行完后,取报告(@?/rdbms/admin/awrrpt)

Ø 分析报告(重点关注top 5 time events)

3 性能分析

3.1 JVM分析

3.1.1 堆分析

为了不影响线上的性能,可以使用堆转储,命令如下:

jmap -dump:live,format=b,file=heap_dump.hprofpid

然后可以将生成的.hprof文件导入mat,或者jvisualvm进行分析,可以了解哪些对象正在消耗内存。同时对于识别由创建太多某一特定对象所引发的内存问题,软件提供的直方图方法快速且方便。

3.1.2 垃圾回收分析

Jvm启动时,可以设置-Xloggc,-XX:PrintGCDetails等参数,开启gc日志收集。也可以使用jstat进行监控分析,比如jstat–gcutil pid 2用于每隔2秒打印当前Java堆及GC情况。

3.1.3 线程分析

使用jdk自带的JMC和jstack工具,可以查看堵塞的线程。JMC内部集成的JFR可以很方便的检索出引发线程堵塞的事件。而jstack在一定程度上可以检查线程是堵塞在什么资源上。以下给出jstack定位思路:

JAVA性能优化思路探究

4 性能优化

在深度优化系统前,应该先弄清为何CPU的使用率低。优化代码的目的是提升而不是降低更短时间内的CPU使用率。

4.1 JVM启动参数优化

4.1.1 原生内存的优化

对原生内存的优化,包含使用压缩的OOP(jvm启动参数上增加-XX:+UseCompressedOops)以及调整大内存分页(同时修改linux配置以及jvm启动参数-XX:LargePageSizeInBytes)等,都可以提升性能。

4.1.2 垃圾回收机制的优化

Ø 合理设置堆的大小,以及合理设置好代空间的划分:设置太小容易频繁GC,而设置太大,GC时停顿时间太长。同时为了避免可能使用到虚拟内存,内存页交换导致更慢,至少保留1G的物理内存。

Ø 如何选择各分区大小应该依赖应用程序中对象生命周期的分布情况:如果应用存在大量的短期对象,应该选择较大的年轻代;如果存在相对较多的持久对象,老年代应该适当增大。

Ø 稳定与震荡的堆大小:将-Xms和-Xmx的大小一致,对垃圾回收有利。

4.1.3 大对象分配优化

Ø 大对象尽量分配在TLAB,如果大量发生在TLAB外,需要考虑调整TLAB参数,或者减少分配对象的大小。可以通过-XX:PrintTLAB标志查看结果。

Ø 大对象划入老年代:将大对象直接分配到老年代,保持新生代对象的结构的完整性,以提高GC效率,以通过
-XX:PretenureSizeThreshold设置进入老年代的阀值。

4.2 java编程优化

因为实际的编程中,涉及性能优化的点比较多,以下只是列举一些常见的优化项供参考。

4.2.1 线程池优化

Ø 根据当前服务器CPU的数量合理设置最大线程数,最小线程数,线程池任务队列大小。CPU密集型任务配置尽可能小的线程,如配置Ncpu+1个线程的线程池。IO密集型任务则由于线程并不是一直在执行任务,则配置尽可能多的线程,如2*Ncpu。

Ø 建议使用有界队列,有界队列能增加系统的稳定性和预警能力。

Ø 优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理。

Ø 执行时间不同的任务可以交给不同规模的线程池来处理,或者也可以使用优先级队列,让执行时间短的任务先执行。设置线程的优先级。

4.2.2 其它编程细节

Ø 尽量减少内存的使用,减少对象的大小,设置类型时考虑最小原则,去掉不用的属性,以及没有用到的实例变量。

Ø 通过使用对象池以及线程局部变量的方式来加强对象的重复。对象重用跟GC是有点矛盾,所以主要考虑对象初始化时成本比较高的情况(即初始化时间比较长)。

Ø 对于保存实际不需要在多个线程间共享的同步对象,同时又在不同的实际中进行传递的对象,可以考虑使用线程局部变量,减少同步竞争。

Ø 在一些场景下,优化使用java8并行流的模式

4.3 数据库优化

4.3.1 使用预编译

使用preparedStatement方式,重用预处理语句池可以极大提升性能,同时也要避免出现大量大型对象池化而引起的GC方面的问题。

4.3.2 使用连接池

引入hikari连接池,在启动时就配置好

Ø 创建连接的代价很大,通过JDBC连接池获取连接可省去创建连接时间。同时需要合理设置连接池的大小。

Ø 合理设值:比如设置检索时的批量值,设置最优的预取值,设置ResultSet的批量值,可以提高检索的性能。

Ø 事务的优化:事务的提交以及事务相关的锁机制都会影响系统的性能,需要考虑合理设置事务隔离的级别,以及批量提交的策略等。

5 性能实战经验汇总

5.1 清算并发性能上不去

5.1.1 问题的现象

使用java8的并行流计算时,发现并发的性能上不去,并且性能会随着时间推移,不断的下降

5.1.2 优化点

Ø 引入hikari连接池,将单笔延时降到5ms

Ø 关闭日志

Ø 将sql改成预编译的模式

Ø Oracle服务器的把oracle的内存提高

5.2 Hsiar跟中台的连接上,存在很多FIN_WAIT2连接

5.3 Server_name是否可以随便配置

6 小结

6.1 性能工具箱

6.1.1 压测工具jmeter

Jmter是开源的压测工具,也易于上手。它的使用就不介绍了,这里主要讲一些注意的事项:

Ø 它的实时绘图依赖于服务器端的响应,如果压测机与服务器时间不同步的话,会出现展示图断层现象,为了得到更准确的性能曲线,建议使用命令行的方式。

Ø 有时候发现压测性能上不去,有可能的原因在于客户端。主要考虑的因素:客户端的CPU不足以支持所需数量的客户端线程,或者客户端需要花大量时间处理响应后才能发送请求。

6.1.2 JVM相关

除了上文提到的jdk自带的工具外,还有IBM提供的MemoryAnalyzer,以及商用软件jprofile都很强大。

6.1.3 数据库相关

对于数据库的性能监控,可以使用Spotlight,它有基于mysql以及oracle的不同版本支持。

6.1.4 网络相关

常用Linux自带的Tcpdump命令导出抓包,然后使用wireshark进行分析,很强大。

本文主要是针对java性能调优的一般思路的总结,以及分享一些在性能优化上常用的最佳实践。希望对大家有帮助。


推荐阅读
  • CAS 机制下的无锁队列设计与实现 ... [详细]
  • 在处理遗留数据库的映射时,反向工程是一个重要的初始步骤。由于实体模式已经在数据库系统中存在,Hibernate 提供了自动化工具来简化这一过程,帮助开发人员快速生成持久化类和映射文件。通过反向工程,可以显著提高开发效率并减少手动配置的错误。此外,该工具还支持对现有数据库结构进行分析,自动生成符合 Hibernate 规范的配置文件,从而加速项目的启动和开发周期。 ... [详细]
  • 服务器部署中的安全策略实践与优化
    服务器部署中的安全策略实践与优化 ... [详细]
  • 该大学网站采用PHP和MySQL技术,在校内可免费访问某些外部收费资料数据库。为了方便学生校外访问,建议通过学校账号登录实现免费访问。具体方案可包括利用学校服务器作为代理,结合身份验证机制,确保合法用户在校外也能享受免费资源。 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
  • POJ 2482 星空中的星星:利用线段树与扫描线算法解决
    在《POJ 2482 星空中的星星》问题中,通过运用线段树和扫描线算法,可以高效地解决星星在窗口内的计数问题。该方法不仅能够快速处理大规模数据,还能确保时间复杂度的最优性,适用于各种复杂的星空模拟场景。 ... [详细]
  • 阿里云MySQL与Oracle数据库的主从复制技术详解 ... [详细]
  • 在深入掌握Spring框架的事务管理之前,了解其背后的数据库事务基础至关重要。Spring的事务管理功能虽然强大且灵活,但其核心依赖于数据库自身的事务处理机制。因此,熟悉数据库事务的基本概念和特性是必不可少的。这包括事务的ACID属性、隔离级别以及常见的事务管理策略等。通过这些基础知识的学习,可以更好地理解和应用Spring中的事务管理配置。 ... [详细]
  • 本文深入解析了Java 8并发编程中的`AtomicInteger`类,详细探讨了其源码实现和应用场景。`AtomicInteger`通过硬件级别的原子操作,确保了整型变量在多线程环境下的安全性和高效性,避免了传统加锁方式带来的性能开销。文章不仅剖析了`AtomicInteger`的内部机制,还结合实际案例展示了其在并发编程中的优势和使用技巧。 ... [详细]
  • TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得
    TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得 ... [详细]
  • 帝国CMS中的信息归档功能详解及其重要性
    本文详细解析了帝国CMS中的信息归档功能,并探讨了其在内容管理中的重要性。通过归档功能,用户可以有效地管理和组织大量内容,提高网站的运行效率和用户体验。此外,文章还介绍了如何利用该功能进行数据备份和恢复,确保网站数据的安全性和完整性。 ... [详细]
  • 在2015年1月的MySQL内核报告中,我们详细探讨了性能优化和Group Commit机制的改进。尽管网上已有大量关于Group Commit的资料,本文将简要回顾其发展,并重点分析MySQL 5.6及之前版本中引入的二进制日志(Binlog)对性能的影响。此外,我们还将深入讨论最新的优化措施,如何通过改进Group Commit机制显著提升系统的整体性能和稳定性。 ... [详细]
  • 深入浅析JVM垃圾回收机制与收集器概述
    本文基于《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》的阅读心得进行整理,详细探讨了JVM的垃圾回收机制及其各类收集器的特点与应用场景。通过分析不同垃圾收集器的工作原理和性能表现,帮助读者深入了解JVM内存管理的核心技术,为优化Java应用程序提供实用指导。 ... [详细]
  • 如何利用Java 5 Executor框架高效构建和管理线程池
    Java 5 引入了 Executor 框架,为开发人员提供了一种高效管理和构建线程池的方法。该框架通过将任务提交与任务执行分离,简化了多线程编程的复杂性。利用 Executor 框架,开发人员可以更灵活地控制线程的创建、分配和管理,从而提高服务器端应用的性能和响应能力。此外,该框架还提供了多种线程池实现,如固定线程池、缓存线程池和单线程池,以适应不同的应用场景和需求。 ... [详细]
  • 在Python网络编程中,多线程技术的应用与优化是提升系统性能的关键。线程作为操作系统调度的基本单位,其主要功能是在进程内共享内存空间和资源,实现并行处理任务。当一个进程启动时,操作系统会为其分配内存空间,加载必要的资源和数据,并调度CPU进行执行。每个进程都拥有独立的地址空间,而线程则在此基础上进一步细化了任务的并行处理能力。通过合理设计和优化多线程程序,可以显著提高网络应用的响应速度和处理效率。 ... [详细]
author-avatar
steveukuk
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有