什么都没动!应用系统又双叒起不来了
前言
应用系统起不来是个非常常见的问题。这种现象特别容易在非生产环境出现。由于系统依赖 的一些外置资源,如数据库/redis等宕机(这个测试环境还是容易发生的)。就会导致系统一行代码都没有改,仅仅重启了下,就起不来的尴尬现象!
痛点
事实上,如果有对应的错误日志,我们还是很容易通过异常堆栈去判断到底哪个地方有问题的。有迹可循的错误当然好搞,最怕的就是系统启动的时候卡主了,什么都不输出!这时候由于没有任何信息,我们很难判断出原因,往往耗费大半天时间。
方法
今天笔者就介绍遇到这种情况常用的方法。我们知道,一个Java进程启动时候肯定有个主线程去做一系列的操作,例如SpringBoot/Tomcat的启动主线程就叫做main(JBoss的叫StartStop)。而这个主线程在启动成功后会打出
2020-09-25 13:38:51.089 INFO 59380 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8090
这样类似的信息。如下图所示:
所以,如果没有任何日志输出而且系统无法提供任何服务的话,大部分情况下是Main线程运行一个耗时的操作卡住了!如下图所示:
这时候,我们就需要知道到底Main线程卡在哪里,很简单,使用jstack!
jstack -l 你的进程id > stack.txt
如果你不知道你的Main线程叫什么名字,翻下已打印出来的日志,启动时候出现最多的那个线程名字大概率就是Main线程,而且名字也应该比较容易联想(什么Main啊,StartStop之类的)。jstack会将当时Java进程所有的线程Dump出来。我们只需要在里面搜索一下Main线程名字 对应的关键字即可,例如"main"
less stack.txt
less中寻找main,可能有多个main,名字最精确匹配的那个即可
例如笔者的一个例子:
stack.txt
"main" #1 prio=5 os_prio=0 tid=123456 nid=123 runnable [0x00213]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
......
at oracle.net.ns.Packet.Receive(Packet.java:300)
......
at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:156)
......
at java.lang.reflect.Method.invoke(Method.java:498)
......
at org.springframework.boot.loader.JarLauncher.main(JarLuncher.java:51)
千万不要被这个RUNNABLE给骗了,在Java进程陷入系统调用后,线程状态依旧是RUNNABLE。如果吃不准,可以再jstack一次,看看是否两次线程都卡在同一段代码上。仔细观察下堆栈,就发现卡在druid数据源连接数据库上面!
有了这个信息,就好办了,问题基本就可以轻松定位了。自己用工具去连一下关联的数据库,看看是否能够连接成功即可。笔者连了一下对应的数据库,果然不通,找了下DBA,拿到了新的地址,问题就解决了!
推荐一本书,这本书非常赞,豆瓣评分9.7!笔者看过之后大呼过瘾!绝对物超所值!
总结
好了,今天的分享就到此结束。如果系统起不来,看上去就卡主了,就按照下面的脑图分析。就能解决很多很多问题了!这是个实用的小技巧,希望对你有所帮助。