1.使用top查看CPU使用情况,发现用户为app的java进程CPU使用率近400%(4核CPU),记录下PID。(说明:系统恢复正常后的截图)
2.查看该进程中线程CPU使用率,使用top -Hp pid 查看各线程情况,并记录下CPU使用率高的线程ID(说明:系统恢复正常后的截图)
现场截图为:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5298 channel 20 0 7193m 1.8g 30m S 85.7 11.7 1:27.34 java
3.使用jstack做Thread dump线程转储,转储包含了JVM中所有存活的线程,找出CPU使用率高的线程
3.1用app用户登录,使用jstack pid > threaddump*.log命令进行Thread dump(pid为步骤一的PID,log文件名可以自定义命名规则)
3.2由于应用服务器的CPU忽高忽低,所以在执行步骤3.1的同时,记录下步骤二的使用CPU高的线程ID,方便对照查找
4.将线程pid转成16进制,在生成的thread dump文件中查找对应的nid,定位问题
4.1使用 printf ‘%x \n’ pid 生成16进制值
4.2使用16进制的值在thread dump文件中查找,如下图所示
在dump中,线程一般存在如下几种状态:
1、RUNNABLE,线程处于执行中
2、BLOCKED,线程被阻塞
3、WAITING,线程正在等待
5.由于服务器的故障现象是CPU会陡增,然后在恢复正常,一直循环出现。执行多次thread dump查看CPU高是否为同一问题引起,重复步骤2、3、4即可。多次thread dump后的问题定位都指向同一行代码。
6.由于怀疑受网络影响,进行tcpdump抓包,分析后排除
6.1通讯端口为18888,使用netstat -an|grep 18888查看,如下图所示
使用netstat查看18888端口,发现很多状态为CLOSE_WAIT状态
常用的四个状态是:ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭,LISTEN侦听来自远方的TCP端口的连接请求
6.2 网络抓包,用root用户登录,使用 tcpdump -i eth0 port 18305 and host ip -vv -s0 -w /tcpdumppkg.pcap 抓包
6.3使用wireshark或dali打开tcpdumppkg.pcap文件,另外一个应用没返回字节给当前应用导致从流中一直读不到字节数,直到超时。
后续优化监控功能
- 应用系统增加输出成功日志的监控
- 对网络连接状态为CLOSE_WAIT(被动关闭)的个数进行监控,语句为:netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'