项目使用jdk1.7,tomcat7用来部署应用。
上线之后,每天不定时宕机。看系统输出日志。没有任何输出,就是在某个时间点突然不再打日志,看catalina.out的输出,也是一样。并没有报错。
往前回溯,日志一切正常。
使用指令 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 查询;
TIME_WAIT 67
CLOSE_WAIT 155
ESTABLISHED 24
CLOSE_WAIT状态的一个很大可能性:当使用httpClient时,由于对方的服务器突然中断,导致在最后一步没有收到返回信息,就处于CLOSE_WAIT了。如果程序中没有设定超时时间,那么就会一直等待,不会结束CLOSE_WAIT状态。
翻查代码,项目中使用的是com.sun.jersey.api.client.Client。没有设置超时时间,jersey默认是永久等待,不会超时的。
果断增加超时时间,补丁系统。
but,第二天,系统依旧不定时宕机。。崩溃ing........
继续研究,CLOSE_WAIT还有一个配置是在liunx中。配置超时时间。
sysctl -w net.ipv4.tcp_keepalive_time=600
sysctl -w net.ipv4.tcp_keepalive_probes=2
sysctl -w net.ipv4.tcp_keepalive_intvl=2
增加配置,之后继续观察。
宕机。。。。。。。。
内心略崩溃。。。
回到一开始的现象,日志突然中断,会不会是log4j的锅呢?
用jmap命令(到jdk的bin目录下,需要用启动tomcat的账户执行,不然会报无权限的)
./jmap -dump:format=b,file=/apps/log/dump.bin 30809,拿到堆栈信息;
./jstack -l 30809 >apps/log/jstack.txt 拿到内存信息;
发现,很多线程都在等待写log.看了下log4j的实现,
翻阅log4j源码,发现存在同步锁。
检查宕机前的日志,发现每次都有一个超长(超过3000字符的日志)打印出来。推测是日志过大,导致log4j被锁,从而宕机。
缩减日志量,继续观察。
系统终于正常了。