网站建设维护问题,企业信息系统的作用,创新的网站建设,php网站开发能挣多钱Java web应用性能分析之【java进程问题分析概叙】-CSDN博客
Java web应用性能分析之【java进程问题分析工具】-CSDN博客
Java web应用性能分析之【jvisualvm远程连接云服务器】-CSDN博客 由于篇幅限制、前面三篇讲了准备工作和分析小结#xff0c;这里将详细操作java进程问题…Java web应用性能分析之【java进程问题分析概叙】-CSDN博客
Java web应用性能分析之【java进程问题分析工具】-CSDN博客
Java web应用性能分析之【jvisualvm远程连接云服务器】-CSDN博客 由于篇幅限制、前面三篇讲了准备工作和分析小结这里将详细操作java进程问题分析定位。
1.java进程常见问题汇总 Java Web应用中的java进程问题从系统表象来看归结起来总共有四方面CPU、内存、磁盘、网络。具体包括 CPU问题CPU 使用率峰值突然飚高问题cpu占用率、ws上下文切换频繁、load avg飙高死循环或者循环嵌套锁等待问题、死锁问题GC问题、线程池大小配置是否合理等等。 内存问题物理内存不足、溢出 (泄露)、OOM堆、栈、元空间、线程、找jvm中的大对象、jvm配置是否合理堆大小是否合适、元空间大小是否合适、NewRatio和SurvivorRatio是否合适、线程栈大小是否合适、如何选择GC收集器、等等jvm调优问题 磁盘问题磁盘空间不足或者满了、log4j日志写磁盘慢阻塞业务请求、物理磁盘性能差、操作系统的io调度算法elevatordeadline这个算法试图把每次请求的延迟降至最低。该算法重排了请求的顺序来提高性能 网络问题网络流量异常、网络攻击、服务器带宽不足、网络io零拷贝dubbo支持零拷贝、web服务器io模型Nginx、Tomcat等。 业务问题业务高并发带来的PV 量过高、服务调用耗时异常、线程死锁、多线程并发问题、频繁进行 Full GC等问题业务逻辑问题具体场景具体分析、如何定位某个方法耗时很久如何统计业务逻辑内每个环节方法的耗时。 备注上面把问题分成5个方面其实这些问题之间都是相互关联的在我们分析问题时不应该将其独立对待简单的归类分析。比如jvm的堆内存不足会导致频繁的fullGC此时的服务器表象可能是cpu飙高甚至大于100%磁盘io性能不足阻塞cpu也可能导致cpu繁忙。 2.问题分析定位一般操作步骤 一般我们的问题都来自监控的报警cpu、内存、磁盘、业务服务接口耗时等等超过了监控平台的阈值就会有短信、邮件发给相关责任人。当然这个时候一般就比较严重了因为已经是生产问题可能涉及到你的kpi和白花花的银子。而且在生产环境排查问题比较麻烦很有可能你连登录服务器的权限都没有。所以尽量在开发环境、测试环境提前发现和解决问题。 在开发环境、测试环境一般没有生产环境的数据尽量模拟产生大量数据的生产环境。还有一个就是通过ab等压测工具模拟高并发尽量还原生产环境的现场。针对环境一般分成离线分析和在线分析。
压测工具参考Java web应用性能分析之【压测工具ab】-CSDN博客
Java web应用性能分析之【高并发之缓存-多级缓存】-CSDN博客
Java web应用性能分析之【高并发之限流】_web服务限流-CSDN博客
Java web应用性能分析之【高并发之降级】-CSDN博客 2.1离线分析
1.查看日志文件检查java应用程序的日志文件通常位于/logs目录下或者由日志配置文件指定。一般可以通过启动springboot进程的bash脚本来查看具体日志文件路径。
2.分析堆栈跟踪如果应用程序崩溃在日志文件中查找异常堆栈跟踪。如oom后的内存dump文件在java进程启动时添加参数确保发生oom时保存现场 -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPathlog/
分析内存使用情况使用诸如JVisualVM, JProfiler, 或MAT (Memory Analyzer Tool) 等工具分析内存使用情况和潜在的内存泄漏。分析线程活动使用线程分析工具如JVisualVM, YourKit, 或MAT来查看线程的状态和死锁。
3.分析JVM参数如果可用分析启动Spring Boot应用程序时使用的JVM参数。一般启动springboot进程的bash脚本在bash脚本中可以查看jvm参数设置如果时查询线上的 则可以用ps -ef|grep java 或者 jinfo pid来查看。
4.分析系统属性和环境变量查看系统属性和环境变量这些可能影响应用程序的行为。
5.分析配置文件检查application.properties或application.yml配置文件查看是否有不正确的配置。
6.分析GC日志如果有GC日志分析垃圾收集器的行为和内存回收情况。要求jvm启动参数配置-XX:PrintGCDateStamps -XX:PrintGCDetails -XX:PrintHeapAtGC -XX:PrintCommandLineFlags -Xloggc:log/gc.log 将gc日志单独保存出来。分析jvm的堆栈元空间大小是否合适结合分析堆栈跟踪文件定位oom、死锁触发的点再去调整代码。
7.历史监控如发生问题时间段的zabbix、prometheus等等通过监控分析这段时间的cpu、内存、io、网络、qps统计、耗时统计。
8.分析应用的外部依赖如数据库、Redis缓存、消息队列KFK、网络服务等等确认是否有问题。 综合上述情况再分析定位问题。 2.2 在线分析 再次申明“在线分析”这个只针对开发环境和测试环境如果是生产环境出了问题概不负责。在线分析一般步骤如下通过top命令找出资源占用高的java进程然后通过top -Hp或者pidstat -p 定位高消耗的线程再通过jstack或者jmap 导出堆栈信息最后用分析工具如JVisualVM, YourKit, 或MAT来分析线程的状态和死锁以及分析内存使用情况和潜在的内存泄漏更加这些问题触发点再去调整代码然后再接着更新代码验证问题是否解决。 当然在已知要分析功能服务的情况下可以直接用JVisualVM远程连接该进程查看具体的资源消耗情况这个图形工具更直观。 JVisualVM参考Java web应用性能分析之【jvisualvm远程连接云服务器】-CSDN博客 ab压测模拟并发环境参考Java web应用性能分析之【压测工具ab】-CSDN博客 步骤1.找出耗时线程 ,18281,转成16进制 printf “%x\n” 18281 pidstat -p 18227 -t 1 10 和top比pidstat是留痕的每次打印都是能看到top是实时刷新但是top可以选择按照cpu或者内存来排序 步骤2.定位线程在干嘛 jstack 18227 |grep 4769 -C5 --color 步骤3.查看代码“at com.zxx.study.web.task.FullCPUTask.run(FullCPUTask.java:15)”找到触发点分析原因再进行修正而且更新代码验证问题是否修复。 2.用JVisualVM来监控分析就简单多了可以很清晰看到cpu和内存消耗情况 抽样器中很直接就能找到占用cpu时间较多的线程 很容易找到触发点和上面的jstack找的位置一样“at com.zxx.study.web.task.FullCPUTask.run(FullCPUTask.java:15)”找到触发点分析原因再进行修正而且更新代码验证问题是否修复。 3.用arthas来分析定位稍后补充。 2.CPU问题 CPU问题CPU 使用率峰值突然飚高问题cpu占用率、ws上下文切换频繁、load avg飙高死循环或者循环嵌套锁等待问题、死锁问题GC问题、线程池大小配置是否合理等等。 cpu飙升带来的影响
响应时间延长CPU使用率过高会导致进程无法及时处理请求从而导致Web应用的响应时间延长影响用户体验。
性能下降高CPU使用率会消耗系统资源导致其他进程或服务的性能下降可能引起整体系统的不稳定性。
可用性降低CPU使用率过高持续一段时间可能导致Web应用崩溃或无法正常运行从而降低系统可用性。java进程导致cpu飙升的原因和解决方法
Java进程导致CPU使用率飙升的原因可能有多种以下是一些常见原因及其解决方法大量并发请求大量并发请求时可能会导致CPU使用率升高特别是在处理复杂的请求或计算密集型任务时。
解决方法架构优化、引入负载均衡无限循环或长时间执行的代码检查是否有死循环或者复杂的算法导致CPU长时间被占用。
解决方法优化代码逻辑确保循环有明确的退出条件。过多的线程竞争如果有多个线程竞争同一资源或者执行同步块可能会导致CPU使用率升高。
解决方法减少线程数量优化同步策略使用更高效的并发工具。线程死锁竞争资源多个线程同时竞争有限的资源当资源分配和释放不当时可能会导致死锁循环等待线程之间相互等待对方释放资源形成循环等待的局面。
解决方法重新定义竞争的资源调整循环等待。内存泄漏如果Java进程中存在内存泄漏可能会导致GC频繁运行消耗大量CPU资源。
解决方法使用内存分析工具检查并修复内存泄漏问题。JIT (Just-In-Time) 编译问题Java虚拟机的JIT编译器可能会花费更多时间优化代码。
解决方法监控应用运行情况如果发现编译耗时过长可能需要优化代码结构。gc问题频繁gc导致cpu飙升
解决方法调整垃圾收集器的参数或者使用不同的垃圾收集器jvm堆设置不合理调整堆大小设置大对象导致频繁gc可以分批加载数据控制进入jvm的数据量如mybatis中的fetchSize 以及 jdbc:mysql://localhost:3306/mydb?cursorScrollabletruedefaultFetchSize100
。外部库或依赖引起的问题某些外部库可能在后台执行大量的计算或等待资源导致CPU使用率升高。
解决方法检查依赖库的文档确保它们被正确管理和使用。系统调用或IO操作过多的系统调用或IO操作可能会导致CPU等待硬件资源从而使CPU使用率升高。
解决方法优化IO操作减少不必要的系统调用。外部因素如果Java进程依赖于外部服务或资源并且这些服务出现瓶颈或不稳定可能会导致CPU使用率上升。
解决方法监控和确保外部依赖的稳定性和性能。在实际处理时可以使用如下工具和技术来诊断和解决问题
使用top或htop命令查看哪个Java进程的CPU使用率高。
使用jstack工具获取Java线程的堆栈信息。
使用jstat工具监控JVM的各种运行状态如垃圾收集信息。
使用Java性能分析工具如VisualVM, JProfiler, YourKit进行详细分析。
优化代码逻辑减少不必要的计算或等待。
升级或更换不够高效的组件和库。
调整系统配置如分配更多的资源给Java进程。总之要解决Java进程导致的CPU使用率高的问题需要定位具体的原因并根据原因采取相应的解决措施。Mybatis的游标大小fetchSize
Options(resultSetType ResultSetType.FORWARD_ONLY, fetchSize Integer.MIN_VALUE)
Select(select domain from illegal_domain where icpstatus ! #{icpstatus})
CursorIllegalDomain getDayJobDomain(Param(icpstatus) Integer icpstatus);
注意游标是可以前后移动的。如果resultSetType TYPE_SCROLL_INSENSITIVE 就是设置游标就可以前后移动。
Mybatis为了保证可以前后移动Mybatis会把之前查询的数据一直保存在内存中。
所以并不能根本解决OOM所以我们这里需要设置为Options(resultSetType ResultSetType.FORWARD_ONLY)(其实默认就是ResultSetType.FORWARD_ONLY)3.内存问题 内存问题物理内存不足、溢出 (泄露)、OOM堆、栈、元空间、线程、找jvm中的大对象、jvm配置是否合理堆大小是否合适、元空间大小是否合适、NewRatio和SurvivorRatio是否合适、线程栈大小是否合适、如何选择GC收集器、等等jvm调优问题 内存飙升分析思路
1.排查进程占用内存
使用top命令、JVisualVM工具、或者普罗米修斯等工具查看java进程内存占用情况。
2.分析内存使用情况 使用jstat或者JVisualVM工具查看Full GC情况分析full gc次数是否频繁确认应用本身是否有问题。 使用jmap、jcmd查看当前应用进程使用内存分析是否存在内存飙升等问题。从JDK 7开始提供jcmd拥有jmap的大部分功能官方推荐使用jcmd命令替代jmap命令。 JVisualVM导出jvm进行分析。 分析gc日志确认gc次数和单次耗时用来判断是否有问题。
jvm调优稍后补充。 导致内存飙升的原因和解决方法
原因可能包括内存泄漏Memory Leak对象不再被使用但垃圾回收器无法回收因为还有活跃的引用。大量对象创建比如在循环中创建大量的临时对象。分配了过大的数组或集合可能超过了JVM堆大小限制。线程堆栈大小不足每个线程默认有1MB的堆栈大小过多线程可能会导致内存增加。JNI调用如果使用了Native方法可能会有内存分配在C/C层面而不被JVM管理。系统虚拟内存不足系统分配的虚拟内存大小超过了物理内存加交换空间的总和。解决方法使用内存分析工具如MAT, VisualVM等找出内存泄漏的位置并修复代码。优化代码减少不必要的对象创建。监控和调整JVM的堆大小参数例如 -Xms 和 -Xmx 来限制JVM使用的内存。大对象跳过年轻代、直接放入老年代。分析线程使用情况必要时减少线程数量或增加线程堆栈大小。重新分配或优化JNI调用确保正确管理内存。检查系统资源增加物理内存或调整交换空间的大小。具体解决方案取决于实际情况的分析结果。内存飙升常见原因
其他应用Redis、Kafka占用总内存
解决top命令排除。启动参数内存值设定的过小
解决-Xms-Xmx。内存中加载的数据量过于庞大数据缓存、PDF字体缓存、文件传输
解决代码走查观察内存波动。List、MAP等集合中对对象的引用使用完后未清空使得JVM不能回收
解决代码走查观察内存波动。代码中存在死循环或循环产生过多重复的对象实体
解决代码走查。4.磁盘问题 磁盘问题磁盘空间不足或者满了、log4j日志写磁盘慢阻塞业务请求、物理磁盘性能差、操作系统的io调度算法elevatordeadline这个算法试图把每次请求的延迟降至最低。该算法重排了请求的顺序来提高性能 java进程导致io飙升的原因和解决方法
Java进程导致IO飙升可能是由以下几个原因造成的文件读写不当可能是因为Java进程在进行大量的读写操作尤其是在创建和写入临时文件时。网络操作Java进程可能在进行大量的网络输入输出尤其是在进行大量的网络通讯或下载文件时。内存映射文件内存映射文件会占用较多的IO资源尤其是在进行大文件读写时。日志记录过多的日志记录可能会导致IO性能下降尤其是当日志文件过大时。配置问题错误的文件系统配置或者IO调度策略可能导致IO性能问题。解决方法优化文件读写减少不必要的文件读写操作使用缓冲和合适的数据结构来减少IO次数。优化网络操作减少不必要的网络操作优化网络传输效率使用NIO来提高网络通讯性能。优化内存映射文件适当管理内存映射文件的使用确保文件映射在不需要时能够正确关闭。优化日志记录合理控制日志级别使用异步日志记录来避免IO性能瓶颈适当地轮换日志文件。调整系统配置根据具体的IO需求调整文件系统的配置比如调整IO调度策略等。具体解决方案需要根据实际情况分析确定 5.网络问题 网络问题网络流量异常、网络攻击、服务器带宽不足、网络io零拷贝dubbo支持零拷贝、web服务器io模型Nginx、Tomcat等。
Java进程导致网络峰值增高的原因可能有多种常见的原因包括高频发送数据Java应用可能会因为频繁发送网络请求或处理大量数据而导致网络使用率提高。网络延迟Java应用可能因为网络延迟或者频繁的网络连接/断开造成网络流量的增加。内部缓冲区溢出Java进程在处理网络数据时可能因为缓冲区不足导致不断发送数据包增加网络负载。解决方法优化网络通信减少不必要的网络通信实现更高效的数据传输协议。流量控制使用流量控制机制比如TCP拥塞控制限制发送速度。缓冲区管理确保Java应用有足够的缓冲区空间避免溢出问题。网络监控与分析使用网络监控工具分析Java进程的网络使用情况找出峰值所在进行相应优化。具体解决方案需要根据实际的网络使用情况和Java应用的具体行为来制定。 6.业务问题 业务问题业务高并发带来的PV 量过高、服务调用耗时异常、线程死锁、多线程并发问题、频繁进行 Full GC等问题业务逻辑问题具体场景具体分析、如何定位某个方法耗时很久如何统计业务逻辑内每个环节方法的耗时。 业务问题这个原因很多解决办法倒是很直接功能设计评审和代码走查。 功能设计评审复杂的业务逻辑在编码前给出设计逻辑提交专家组进行评审。 代码走查看人 7.实验的代码
入口controller
package com.zxx.study.web.controller;import com.zxx.study.web.task.FullCPUTask;
import com.zxx.study.web.task.FullIOTask;
import com.zxx.study.web.task.LazyTask;
import com.zxx.study.web.task.SyncThreadTask;
import com.zxx.study.web.util.ApiResult;
import com.zxx.study.web.util.ZhouxxTool;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;/*** author zhouxx* Description:* date 2024/6/2 18:33*/
RestController
Slf4j
Validated
RequestMapping(/api/v1/lock)
public class DeadlockController {Value(${upload.file-path})private String filePath;Value(${server.port})private String serverPort;SneakyThrowsGetMapping(/deadlock)public ApiResult deadlock(RequestParam(value name, required false) String name) {//log.info(hi);/*** 死锁是两个或更多线程阻塞着等待其它处于死锁状态的线程所持有的锁。死锁通常发生在多个线程同时但以不同的顺序请求同一组锁的时候。** 例如如果线程1锁住了A然后尝试对B进行加锁同时线程2已经锁住了B接着尝试对A进行加锁这时死锁就发生了。* 线程1永远得不到B线程2也永远得不到A并且它们永远也不会知道发生了这样的事情。为了得到彼此的对象A和B* 它们将永远阻塞下去。这种情况就是一个死锁。** */Object a new Object();Object b new Object();new Thread(new SyncThreadTask(a, b)).start();ZhouxxTool.sleep(5000);if(name!nullzhouxx.equals(name)) {Thread thread new Thread(new SyncThreadTask(b, a));thread.start();thread.join();}HashMap datanew HashMap();data.put(threadName,Thread.currentThread().getName());data.put(serverPort,serverPort);data.put(name,name);return ApiResult.success(data);}SneakyThrowsGetMapping(/fullcpu)public ApiResult fullcpu(RequestParam(value name, required false) String name) {//log.info(hi);if(zhouxx.equals(name)){//cpu高占用线程new Thread(new FullCPUTask()).start();//空闲线程new Thread(new LazyTask()).start();new Thread(new LazyTask()).start();new Thread(new LazyTask()).start();}HashMap datanew HashMap();data.put(threadName,Thread.currentThread().getName());data.put(serverPort,serverPort);data.put(name,name);return ApiResult.success(data);}SneakyThrowsGetMapping(/fullio)public ApiResult fullio(RequestParam(value name, required false) String name) {//log.info(hi);if(zhouxx.equals(name)){//IO高占用线程new Thread(new FullIOTask()).start();//空闲线程new Thread(new LazyTask()).start();new Thread(new LazyTask()).start();new Thread(new LazyTask()).start();}HashMap datanew HashMap();data.put(threadName,Thread.currentThread().getName());data.put(serverPort,serverPort);data.put(name,name);return ApiResult.success(data);}}
模拟cpu飙高
package com.zxx.study.web.task;/*** 这是一个占有大量CPU资源的任务** author lfg* version 1.0*/
public class FullCPUTask implements Runnable {Overridepublic void run() {while (true) {double a Math.random() * Math.random();}}
}package com.zxx.study.web.task;import com.zxx.study.web.util.ZhouxxTool;/*** 空闲线程** author lfg* version 1.0*/
public class LazyTask implements Runnable {Overridepublic void run() {while (true) {ZhouxxTool.sleep(10000);}}
}
模拟死锁
package com.zxx.study.web.task;import com.zxx.study.web.util.ZhouxxTool;/*** author zhouxx* Description:* date 2024/6/3 14:38*/
public class SyncThreadTask implements Runnable {private Object a;private Object b;public SyncThreadTask(Object a, Object b) {this.a a;this.b b;}Overridepublic void run() {String name Thread.currentThread().getName();ZhouxxTool.printTimeAndThread(name 准备获取锁 a);synchronized (a) {ZhouxxTool.printTimeAndThread(name 已获取锁 a);doWork();ZhouxxTool.printTimeAndThread(name 准备获取锁 b);synchronized (b) {ZhouxxTool.printTimeAndThread(name 已获取锁 b);doWork();}ZhouxxTool.printTimeAndThread(name 释放锁 b);}ZhouxxTool.printTimeAndThread(name 释放锁 a);ZhouxxTool.printTimeAndThread(name 结束);}void doWork() {ZhouxxTool.sleep(5000);}
}
模拟io忙
package com.zxx.study.web.task;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;/*** IO 操作频繁的任务** author lfg* version 1.0*/
public class FullIOTask implements Runnable {Overridepublic void run() {while (true) {try {FileOutputStream fileOutputStream new FileOutputStream(tempFile.txt);for (int i 0; i 10000; i) {fileOutputStream.write(i);}fileOutputStream.close();FileInputStream fileInputStream new FileInputStream(tempFile.txt);while (fileInputStream.read() ! -1) {}} catch (IOException e) {e.printStackTrace();}}}
}模拟oom
参考
Java web应用性能分析之【6种OOM模拟】_java 模拟oom-CSDN博客
Java web应用性能分析之【6种OOM监控和分析】-CSDN博客