记一次服务Connection refused

2018-05-10  本文已影响0人  李昂的数字之旅

起因

服务B上日志显示,请求服务A连接被拒(Connection refused)???

  1. 猜测一 服务进程崩了?

登录时服务A的机器,ps -ef|grpep java查看jvm还在。

  1. 猜测二 端口绑定错了?

服务端口通过配置参数-Dserver.port=8080绑定,
ps -ef|grpep java还是通过这个命令查看,端口是8080没错
telnet 127.0.0.1 8080响应Connection refused
netstat -lntp|grep 8080没有结果。 jvm进程启动成功,端口没绑上去???

  1. 猜测三 服务hang住了或死锁

top -Hp pgrep java查看jvm进程的线程详情,看那个cpu使用率最高,cpu使用并不多,而且cpu使用率也是来回在换,不像死循环。
printf "%x\n" {pid} 找了个相对比较活跃的进程号,格式转为十六进制,准备到打印线程快照找一下是哪个线程有问题。
jstack -l pgrep java > stack.log查看线程,搜索{十六进制},看到是vert.x-eventpool-thread-0线程,状态是RUNNABLE稳稳的。搜索blocked/dead关键字没发现问题。

  1. 猜测四 看一下log文件

最后一段日志是,服务重启了,启动过程中在调用DB相关Bean foo时报org.springframework.beans.factory.UnsatisfiedDependencyException,原因是foo在注册时因为“Too many connections”导致数据库连接不成功,时foo注册失败,spring boot报错,且应用启动失败Application startup failed

这么看来问题已经找到,spring容易启动失败,所以端口也没去绑定。但是spring失败了,为什么jvm没结束???

其实在前面的jstack日志里可以发现原因
grep 'nid=' stack.log|grep -v 'daemon' 查看非守护线程数,还有好几个线程还没结束。
来回顾下jvm结束的条件:所有非守护进程结束时,jvm自动退出

问题总结

问题原因是spring boot在启动因为Bean注册失败,抛异常而启动失败,但由于有其他非守护线程存在,而jvm不能正常结束。

解决方案

通过spring的FailureAnalyzer捕获异常UnsatisfiedDependencyException,把未关闭的线程资源关闭掉,做统一的处理,jvm就能正常关闭。

FailureAnalyzer使用
public class DBFailureAnlyzer extends AbstractFailureAnalyzer<XXXException> {
    @Override
    protected FailureAnalysis analyze(Throwable rootFailure, XXXException cause) {
       //do something
        return new FailureAnalysis("由于xx原因,应用启动失败", "清理存活的线程", cause);
    }
}
在META-INF/spring.factories文件中添加一下内容
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.xx.www.DBFailureAnlyzer,\
com.xx.www.DBFailureAnlyzer1
上一篇下一篇

猜你喜欢

热点阅读