线上java服务不可用,一般分两种情况:
java进程挂掉
1. JVM异常退出
此类情况,会在java进程的启动目录下,发现hs_err_pid***.log文件,通过该日志文件能定位到jvm crash原因。该日志文件的解读参见 jvm crash。一般在使用JNI时,内存分配容易引起crash。
2. 内存溢出,进程被OS杀掉
该类问题的表象是线上服务无端停掉,日志也看不出什么痕迹,此时在linux下可通过dmesg查看相关信息。一般是由于内存不够导致的。
java进程不可用
1. 线程死锁
并发情况下,代码问题引起线程死锁,当请求不断过来,引起线程堆积无法正常结束。一旦线程达到中间件的上限时,中间件将无法响应外部请求,线上表现为进程存在,但服务不能响应。此时通过
jstack pid
能看到线程堆栈信息,通过查找BOLOCKED锁定的资源,定位到死锁位置
2. 线程阻塞
该情况与线程死锁类似,但通过查看堆栈信息,往往找不到哪个资源被锁,如下的jstack报告
"ajp-nio-8009-exec-470" daemon prio=10 tid=0x00007f559c016800 nid=0x4d55 waiting for monitor entry [0x00007f5590e6a000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.util.LinkedHashMap.createEntry(LinkedHashMap.java:442)
at java.util.HashMap.addEntry(HashMap.java:884)
......
"ajp-nio-8009-exec-470" daemon prio=10 tid=0x00007f559c016800 nid=0x4d55 waiting for monitor entry [0x00007f5590e6a000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.util.LinkedHashMap.createEntry(LinkedHashMap.java:442)
at java.util.HashMap.addEntry(HashMap.java:884)
......
日志中有大量的此类线程,也无法看到查到类似
-locked <0x00000000c6eb8560>之类的日志 。
此时应当通过jstat查找gc的相关日志。
原因参见 gc block thread
3.数据库问题
此类问题比较常见,由于db操作不当,引起数据库死锁或等待。死锁通过db console能方便定位,但uncommit引起的锁定位起来就比较费劲。具体来说,应用通过jdbc连接db,在使用事务时,多个操作会共用一个db session,并且此时db session的auto commit是关闭的。若连接未显示commit,且操作后连接也未关闭,此时将会导致该连接的写操作占用的资源一直不释放,若其他请求需要操作同样的数据(写操作),此时会引发锁等待。