上线一个版本运行大概24小时后服务崩溃,查看日志发现奔溃到服务重启的时间没有任何日志输出,初步怀疑是Tomcat假死的问题,由于线上服务,没有权限,只能一步步排查,so,有以下怀疑:
1.请求量变大,Tomcat连接数达到最大。
netstat查看tomcat连接情况
之所以有此怀疑是因为咨询了下前端,线上服务有一个10s和一个20s的轮训,另外观察了下服务器监控,这个时间点cpu飙升到300%,请求数也猛然升高,跟运维同事查看了下线上tomcat连接数,150,然后就调整了下配配置到400,坐等。。。
2.死锁问题
调整了tomcat连接数后发现死的更快了,由于是下班时间,而且线上可用性必须保证,所以立马做了重启,没有拿到任何进程堆栈信息,服务也没有做任何监控,只能猜了,对比了下上线的代码,发现俩台服务都开启了同一个定时任务,并且加了同步锁,以为是这个问题,仔细一想,没什么用。
3.代码问题
由于每次线上崩溃,都要求尽快重启,为了拿到堆栈信息,和运维写了一个监控脚本,并且有问题立马重启,脚本如下:
#!/bin/bash
# 用于小七后台single服务cup占比太高自动重启服务。
ssh_path=/home/SP-in-SEVEN/songwg/tomcat/single_project/bin/
pid=`ps aux | grep sing | grep -v grep | grep -v retomcat | grep -v less | grep -v vim | awk '{print $2}'`
cpu=`ps aux | grep sing | grep -v grep | grep -v retomcat | grep -v less | grep -v vim | awk '{print $3}'`
time=`date +%Y-%m-%d-%H-%M-%S`
if [ $(echo "$cpu >= 50"|bc) = 1 ];then
echo $time杀$pid 进程 >> /root/ssh.restart.log
jstack $pid >> /root/jstack.log
jmap -heap $pid >> /root/jmap.log
netstat -ant | grep 8202 >> /root/jmap.log
kill -9 $pid
cd $ssh_path
./startup.sh >> /root/ssh.restart.log
else
echo $time 当前服务正常 >> /root/ssh.restart.log
fi
echo 当前pid是:$pid >> /root/ssh.restart.log
#echo $ssh_path >> /root/ssh.restart.log
echo 当前cpu占用率:$cpu >> /root/ssh.restart.log
echo $(ps aux | grep sing | grep -v grep | grep -v retomcat ) >> /root/ssh.restart.log
~
此脚本用定时任务10分钟跑一次,因为重启之后cpu不会很快降下来,所以时间10分钟跑一次,避免不停重启,
执行结果如下
上面脚本拿堆栈信息逻辑大概如下:
首先拿到tomcat的PID:ps -ef | grep tomcat
然后查看tomcat下消耗性能最多的线程:top -Hp pid
通过printf "%x\n" 23978打印出这个线程的16进制值
然后通过命令打印出tomcat的堆栈日志 jstack pid> stack.log
4.数据库连接数用尽
拿到堆栈信息后,拿到进程下,并结合日志发现一个问题
查看数据库连接情况并查看有没有死锁:
show variables like '%max_connections%';
show status like 'Threads%';
show full processlist
数据库连接数用完,排查了下这段代码,历史悠久,还是hibernate写的,而且由于数据没有整理过,数据库现在有近3千万的数据,造成超时问题,只能改改改。
5.OOM (排除)
Jdk自带的工具排查各种堆栈信息