一、问题描述
某开发应用接口出现耗时长的问题,后面直接就未响应了。导致调用出现异常。部署在阿里云环境下,我们可以通过阿里云的相关监控和告警,从而进行异常问题的排查和确认。下面是问题的排查过程。希望能帮到大家排查这类型的问题。
二、问题排查
1.JVM监控显示异常。
出现FullGC 和YoungGC的次数和耗时都急剧增加,从而导致服务器调用耗时比较长。
2.观察主机监控。
相关cpu的使用率也在提高,最高达到38%左右。
3、jvm的线程数也提高
4.异常分析。EDAS异常监控和日志异常分析。
发现有存在一些异常,但是没有大批量刷的情况。也检查了相关异常的出现原因。并未发现有导致gc频繁的原因。
5.Nginx超时时间设置:
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
Nginx配置设置了超时时间为30s,因为服务应用代码gc频繁占用cpu资源,导致耗时过长直接返回超时。
6、gc日志文件分析
7、通过dump文件分析问题原因
在生产环境运行一段时间,发现没多久就挂掉了。在通过命令打出对应的dump文件进行分析。常用的命令有 jstack 和 jmap 就行。一般安装了jdk都有带相关的命令。
1.jstack命令打出线程运行情况:
/opt/edas/jdk/java/bin/jstack -l ${pid}> /home/admin/jstack.prof
2.jmap命令打出dump文件:
su - admin/opt/edas/jdk/java/bin/jmap -dump:live,format=b,file=/tmp/dump.hprof ${pid}
然后我们再根据相关的文件进行分析问题的原因。需要把dump文件下载到本地,然后再用相关的工具进行分析。这里我们采用的是jdk自带的工具 jvisualvm.exe 进行分析dump堆栈文件。
直接导入进来就行了。发现存在执行sql查询的结果内存在很多的对象。
从而确认问题的原因是SQL查询的时候扫描全表的几百万条数据返回到应用里,导致应用的内存直接撑爆了。应用变成僵死状态。
通过排查应用sql执行日志文件。确认是哪个sql语句
再通过sql语句来排查代码里的版本修改有没有涉及相关的SQL语句。
来确定这个问题的根本原因是:代码没有进行判断是否为空,底层的服务接口也没有设置默认分页的条数限制。从而导致了这次的事故异常。
三、问题总结
发现服务器出现了频繁的FullGC和YoungGC,导致服务器调用耗时变长。对服务器进行了性能分析,发现服务器内存使用率高,且堆内存不足。针对这个问题,需要进行代码优化,对服务器的内存进行了调整,从而解决了这个问题。代码中可能存在一些性能瓶颈,如循环嵌套过多、重复计算等问题。我也看了下这个版本的提交代码,暂时没发现有哪些明显的类似问题。
四、后续处理方案
具体出现问题的原因需要在测试环境进行测试和调试:为了确保服务器的稳定性和性能,需要对服务器进行了测试和调试,模拟了大量的并发请求,测试了服务器的响应时间、吞吐量、JVM的GC情况等指标。打出对应的dump堆栈文件进行原因分析。找出有问题的代码持续进行优化和改进。可以添加shell脚本定时监控Java进程是否正常运行,以及自动打dump文件和kill掉重启等功能。
以下是一个示例脚本,它将检查Java进程是否正在运行,并在应用程序无法访问时生成堆栈转储文件和堆转储文件:
#!/bin/bash
# 检查Java进程是否正在运行
if ! pgrep -x "java" > /dev/null
then
echo "Java应用程序未启动"
exit 1
fi
# 获取Java进程ID
PID=$(pgrep -x "java")
# 使用curl命令发送HTTP请求以验证应用程序是否可用
if curl --silent --fail http://localhost:8080/health > /dev/null
then
echo "Java应用程序正在运行"
else
echo "Java应用程序无法访问"
# 生成堆栈转储文件
jstack $PID > heap_dump.txt
# 生成堆转储文件
jmap -dump:format=b,file=heap.bin $PID
# 杀死Java进程
kill $PID
echo "已生成堆栈转储文件和堆转储文件,并杀死Java进程"
fi
该脚本与前面的示例脚本类似,但添加了一个jmap命令来生成Java进程的堆转储文件。jmap命令使用-dump选项指定转储文件的格式(在此示例中为二进制格式)和转储文件的名称(在此示例中为heap.bin)。在生成堆转储文件之后,脚本将使用kill命令杀死Java进程。
请注意,在此示例脚本中,jstack命令和jmap命令都输出到文件中。如果您希望将输出发送到标准输出或其他文件,请相应地修改脚本。