前言:
最近一段sso单点登录系统经常收到服务不可用自动重启的报警邮件,因为有做集群,影响较小,所以拖了几个月才开始着手解决这个问题。下面记录一下本次问题解决的过程(有走一些弯路),以做总结,也希望能给正在排查像试问题的同学一些启发:
先看看我的监控脚本
通过crontab 来监听重启
#!/bin/sh
_status=`curl -I -m 40 -o /dev/null -s -w %{http_code} 127.0.0.1`
echo status $_status
if [ $_status -ne 200 ] && [ $_status -ne 302 ]
then
echo start engine......
aws sns publish --message " sso2 检测到web不可用,自动重启" --topic arn:aws-cn:sns:cn-north-1:XXXX:aws-warning
#sleep 180
/usr/bin/sudo /usr/share/tomcat/bin/shutdown.sh
sleep 5
/usr/bin/sudo ps -ef | grep 'tomcat'|grep '-server' | grep -v grep| awk '{print $2}' | xargs sudo kill -9
sleep 2
/usr/bin/sudo /usr/share/tomcat/bin/startup.sh
fi
这边是通过监听本机127.0.0.1 http状态是否正常来判断服务是否可用的,不等于200或者302时发送报警通知,并且自动重启tomcat;
1,怀疑连接数过高,服务器负载压力 服务器为 t2.medium(2cpu,4GB)
当我收到报警邮件的时候,我先连接上服务器,查看tomcat进程确实还在,查看服务器连接情况
netstat -n | awk '/^tcp/ {++y[$NF]} END {for(w in y) print w, y[w]}'
发现有400多的close_wait,查看具体的close_wait。发现都是与aws elb负载均衡器的连接。因为那边默认60秒超时自动断开后,服务器无发响应,所以保持close_wait状态;
2,查看服务器cpu监控
发现当报警发生时,服务器cpu为100%;继续寻找cpu高的原因;
3,查看报警时cpu都在干嘛
修改报警脚本,当发送报警邮件后,让其sleep 180秒再重启,180秒的时间可以让我找到cpu高的进程数,然后再重启,就不影响用户使用了;
1,查看tomcat pid
ps -ef|grep tomcat
2,查看cpu高的线程
top -H -p 26129
3,找到cpu 100%的线程id,转16进制
printf "%x\n" 26213
4.打印该线程堆栈
jstack 26129 |grep 6665 -A 30
通过堆栈信息发现居然是在进行GC操作,-----这很令我感到意外,因为这个服务器只做单点登录的事情,理论上是不会消耗过大内存的。并且从报警邮件的频率来看没有规律。有时候间隔2小时。有时候2天,并且日志里没有oom error日志;
4,查看内存堆栈
既然发现是因为GC操作导致的cpu过高,那么就查看报警时的堆栈信息就好了,
首先修改脚本,在重启tomcat之前 打印堆栈信息
/usr/bin/sudo ps -ef | grep 'tomcat'|grep '-server' | grep -v grep| awk '{print $2}' | xargs sudo jmap -dump:live,format=b,file=heap.bin
5,通过MAT工具分析heap.bin
可以看到这个线程使用了1.6GB的内存。看看它到底在干嘛。
原来是在查询数据库内容。为什么这个接口会需要这么大的内存呢,排查代码发现,原来当用户调用修改密码接口没有输入邮箱或者手机号,这个接口居然没有做参数为空判断,直接去mysql查询用户表,2000w+的用户信息直接把内存撑爆了。
总结
对外接口不能过分依赖前端的表达校验,这个问题在测试线无法重现是因为数量级的不同,同时非重要的分支,测试人员也交容易忽略;通过这次的问题排查,发现了arthas这个工具,还是有不错的收获