SpringBoot的502问题排查及优化

标签: Java 分类: Java 创建时间:2020-11-04 01:11:42 更新时间:2023-10-20 11:23:26

最近这个问题,让我很头大,就是使用nginx进行转发的时候,总是会会出现502错误。

1.进程被意外杀死

这种情况其实就是一直出现502错误,也就是服务不可用的情况。在关键时刻,Spring Boot服务总是不可以使用,查看日志,我发现了是我使用的一个nacos服务无法被找到造成的,导致了Spring Cloud的loadBalancerClient出现服务不可用的现象。刚开始,我以为是nacos出现的问题,于是就去找了nacos的日志,但是因为nacos日志确实太多了,不知道从何查起。于是就先把服务重新启动了一遍,暂时解决了问题。

第二天到公司的时候,又出现了无法找到服务的问题。经过观察,是因为其中一个java进程被莫名奇妙杀死导致的,这个进程就是使用OAuth2编写的认证服务层。为什么每次都是杀死同一个进程呢?让我很不理解。这个时候,我想起了前几天发现的,每次tomcat进程总是被莫名奇妙的杀死的过程。

1
2
3
4
## 查看日志
vim /var/log/messages
## 具体的查看某些日志条目
cat /var/log/messages | grep -C 5 'Out of memory'

当我使用上面相关命令查看系统日志的时候,发现了很多被杀死的进程,但是也只是显示了有java进程被杀死了,但是没有显示是这个进程是什么,叫什么名字,这个让我怎么查呢?

为了应对tomcat莫名其妙被杀死的情况,我当时是写了一个crontab定时脚本,每隔一分钟检查相关的进程是否被杀死,杀死之后,就重新启动该进程。(思来想去,可能这也不是一个长久之计啊)

2.偶尔502情况

除了所有请求都是502的情况,还有就是出现的偶尔502的情况。比如我每隔10秒钟请求一次服务,在十次中,会有连续三次出现502错误,之前,和之后都是返回的200状态码。在我使用top进行查看的时候,发现每次出现502问题的时候,cpu都会很高。

3.排查过程

(1) 首先我同时打开了top工具和浏览器web tool,不断的观察,发现没过20几个请求之后,就会出现一次502。同时我可以获取到cpu使用过高的进程PID,根据PID,找到的程序是gateway网关程序。

(2) 使用 ps 命令多次打印进程id查看,发现只有一个gateway网关程序,一段时间后,PID就会改变。这个主要的原因就是我编写了定时任务,当进程被杀死的时候,会自动重启该进程,导致进程PID改变。

1
2
3
4
5
## 查看进程pid
ps -aux | grep java

## 查看线程使用率
top -Hp <pid>

总结:根据上面的排查,那么可以得出结论,其实就是这个gateway程序cpu占用过高,被系统杀死,然后重启,重启之后,就会产生短暂的502,无法访问的问题。当然,最后的结果,其实也不全是动态路由的问题,主要的原因还是因为定时任务删除了gateway程序,出现的重启现象,但是我又不能给老板说是我自己的问题。

网上的大神总结的如何进行问题的检查的方法:

(1) 通过 top命令查看CPU情况,如果CPU比较高,则通过top -Hp <pid>命令查看当前进程的各个线程运行情况,找出CPU过高的线程之后,将其线程id转换为十六进制的表现形式,然后在jstack日志中查看该线程主要在进行的工作。这里又分为两种情况
如果是正常的用户线程,则通过该线程的堆栈信息查看其具体是在哪处用户代码处运行比较消耗CPU;
如果该线程是VM Thread,则通过jstat -gcutil <pid> <period> <times>命令监控当前系统的GC状况,然后通过jmap dump:format=b,file=<filepath> <pid>导出系统当前的内存数据。导出之后将内存情况放到eclipse的mat工具中进行分析即可得出内存中主要是什么对象比较消耗内存,进而可以处理相关代码;
(2) 如果通过 top 命令看到CPU并不高,并且系统内存占用率也比较低。此时就可以考虑是否是由于另外三种情况导致的问题。具体的可以根据具体情况分析:
如果是接口调用比较耗时,并且是不定时出现,则可以通过压测的方式加大阻塞点出现的频率,从而通过jstack查看堆栈信息,找到阻塞点;
如果是某个功能突然出现停滞的状况,这种情况也无法复现,此时可以通过多次导出jstack日志的方式对比哪些用户线程是一直都处于等待状态,这些线程就是可能存在问题的线程;
如果通过jstack可以查看到死锁状态,则可以检查产生死锁的两个线程的具体阻塞点,从而处理相应的问题。
参考文章:
1.系统运行缓慢,CPU 100%,以及Full GC次数过多问题的排查思路 (提到了很多的工具,jsatck、top工具等, 总结了多个方法)
2.spring cloud gateway cpu使用异常问题排查 (这里有说是日志大量记录导致的,但是我经过查询,发现并不是这种情况)
3.SpringCloud Gateway 动态路由配置导致cpu满载,内存耗完 (因为我也同样配置了动态路由,所以又可能是因为动态路由导致的问题)
4.Spring Cloud Gateway基于CPU使用率实现限流

4.查看系统内存及cpu使用率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
## cpu及内存使用,PID:进程的ID,USER:进程所有者,PR:进程的优先级别,越小越优先被执行
## NI:进程Nice值,代表这个进程的优先值,VIRT:进程占用的虚拟内存,RES:进程占用的物理内存
## SHR:进程使用的共享内存,S:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态
## %CPU:进程占用CPU的使用,%MEM:进程使用的物理内存和总内存的百分
## TIME+:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值
## COMMAND:启动该进程的命令名称
top

## cpu使用率
top -bn 1 -i -c

## 内存占用率
free -m

## VSZ是虚拟内存,RSS是实际使用的内存,单位KB
ps -p ${pid} -o rss,vsz
参考文章:
1.面试官:JAVA进程突然消失怎么办? (主要原因有这三种:linux的OOM killer、JVM自身故障、JVM的OOM)
2.Java进程被杀死排查过程 (操作系统日志/var/log/messages错误日志,主要排查了oom-killer问题)
3.Linux系统查看CPU使用率的几个命令
4.Linux服务器如何查看CPU占用率、内存占用、带宽占用
5.Linux查看内存使用情况方法
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。