from:http://blog.csdn.net/zheng0518/article/details/44943357
問題現象
最后發現線上的zookeeper的日志zookeeper.out 文件居然有6G,后來設置下日志為滾動輸出,參考:
http://blog.csdn.net/hengyunabc/article/details/19006911
但是改了之后,發現一天的日志量就是100多M,滾動日志一天就被沖掉了,這個不科學。
再仔細查看下日志里的內容,發現有很多連接建立好,馬上又斷開:
- 2014-11-24 15:38:33,348 [myid:3] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@1001] - Closed socket connection for client /10.0.0.3:47772 (no session established for client)
- 2014-11-24 15:38:33,682 [myid:3] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@197] - Accepted socket connection from /10.0.0.3:32119
- 2014-11-24 15:38:33,682 [myid:3] - WARN [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@349] - caught end of stream exception
- EndOfStreamException: Unable to read additional data from client sessionid 0x0, likely client has closed socket
- at org.apache.zookeeper.server.NIOServerCnxn.doIO(NIOServerCnxn.java:220)
- at org.apache.zookeeper.server.NIOServerCnxnFactory.run(NIOServerCnxnFactory.java:208)
- at java.lang.Thread.run(Thread.java:745)
- 2014-11-24 15:38:33,682 [myid:3] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@1001] - Closed socket connection for client /10.0.0.0:32119 (no session established for client)
從日志輸出的時間來看,秒連秒斷,非常詭異。排查問題
用netstat查看網絡連接狀態
到client的服務器上查看連接的狀態:
- netstat -antp | grep 2181
發現有很多TIME_WAIT狀態的連接:- tcp 0 0 10.0.0.3:44269 10.0.1.77:2181 TIME_WAIT -
- tcp 0 0 10.0.0.3:43646 10.0.1.77:2181 TIME_WAIT -
- tcp 0 0 10.0.0.3:44184 10.0.1.77:2181 TIME_WAIT -
- tcp 0 0 10.0.0.3:44026 10.0.1.77:2181 TIME_WAIT -
- tcp 0 0 10.0.0.3:43766 10.0.1.77:2181 TIME_WAIT -
但是TIME_WAIT狀態的連接是看不到進程號的。搜索研究了下netstat的參數,發現沒有辦法輸出TIME_WAIT狀態的連接的pid,只好嘗試其它的辦法。再用 jstack -l pid 來查看進程的線程棧,也沒有發現什么異常的東東。查看到有幾個zookeeper連接的線程,但也是正常狀態。
再檢查了機器的IO,CPU,內存,也沒有異常的情況。
沒找到什么有用的信息,只好再研究下netstat的參數:
發現用 netstat -ae 輸出了一些信息:
- tcp 0 0 10.0.0.3:41772 10.0.1.77:eforward TIME_WAIT root 0
- tcp 0 0 10.0.0.3:41412 10.0.1.77:eforward TIME_WAIT root 0
- tcp 0 0 10.0.0.3:24226 10.0.1.77:2181 TIME_WAIT root 0
- tcp 0 0 10.0.0.3:24623 10.0.1.77:2181 TIME_WAIT root 0
發現user是root。于是以為是非Java應用,在不斷地連接zookeeper。于是停止java程序,發現沒有TIME_WAIT連接了。但是確認是Java應用的問題,于是再重啟Java應用,但沒有再發現TIME_WAIT情況。很詭異。問題不能重現了,相當的蛋疼。忽然想到線上的應用也許也有這個問題,于是到線下zookeeper服務器上查看了下,果然發現有同樣的問題。
用tcpdump抓包和wireshark分析
先用tcpdump來查看下具體的網絡連接,發現的確是連接連上再斷開。于是先保存成cap文件,再用wireshark來分析:
- tcpdump -vv host 192.168.66.27 and port 2181 -w 2181.cap
但是也沒有發現什么有用信息,的確是TCP連接連上,再FIN,ACK連接斷開。查看應用日志,發現Tomcat webcontext沒有正常啟動
沒辦法了,有兩種考慮,一個是用strace,二是用btrace。但是btrace好久沒用過了,不太想再去看例子文檔。
還好,去下btrace之后,先去看了下應用的日志,發現應用報了一些ClassLoader的錯誤:
- Nov 24, 2014 7:32:43 PM org.apache.catalina.loader.WebappClassLoader loadClass
- INFO: Illegal access: this web application instance has been stopped already. Could not load org.apache.zookeeper.ClientCnxnSocketNIO. The eventual following stack trace is caused by an err
- or thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.
- java.lang.IllegalStateException
- at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1564)
- at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1523)
- at ch.qos.logback.classic.spi.PackagingDataCalculator.loadClass(PackagingDataCalculator.java:198)
- at ch.qos.logback.classic.spi.PackagingDataCalculator.bestEffortLoadClass(PackagingDataCalculator.java:226)
- at ch.qos.logback.classic.spi.PackagingDataCalculator.computeBySTEP(PackagingDataCalculator.java:132)
- at ch.qos.logback.classic.spi.PackagingDataCalculator.populateUncommonFrames(PackagingDataCalculator.java:107)
- at ch.qos.logback.classic.spi.PackagingDataCalculator.populateFrames(PackagingDataCalculator.java:99)
因為有經驗了,馬上知道這個Tomcat因為其它原因webcontext實始化失敗退出,然后后面的一些線程繼續跑時,會拋出ClassLoader,或者Class not found的異常。于是猜想到原因了:
Tomcat webcontext初始化失敗,zookeeper的重連線程自動不斷重連。
但是為什么重啟Tomcat之后,沒有重現TIME_WAIT的情況?
再折騰了下,發現只有當zookeeper重啟后,應用才會出現大量的TIME_WAIT連接。報的是下面這個異常:
- 2014-11-24 19:42:44,399 [Thread-3-SendThread(192.168.90.147:4181)] WARN org.apache.zookeeper.ClientCnxn - Session 0x149c21809731325 for server 192.168.90.147/192.168.90.147:4181, unexpected error, closing socket connection and attempting reconnect
- java.lang.NoClassDefFoundError: org/apache/zookeeper/proto/SetWatches
- at org.apache.zookeeper.ClientCnxn$SendThread.primeConnection(ClientCnxn.java:867) ~[zookeeper-3.4.5.jar:3.4.5-1392090]
- at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:352) ~[zookeeper-3.4.5.jar:3.4.5-1392090]
這個異常的原因,是某些zookeeper的類沒有加載到。最終原因分析
梳理下整個流程:
- Tomcat啟動,初始化webcontext;
- 初始化spring, spring初始某些些bean,這些bean包括了zookeeper的連接相關的bean;
- 這時zkClient(獨立線程)已經連接上服務器了,但是classloader沒有加載到org/apache/zookeeper/proto/SetWatches類;
- spring初始化失敗,導致Tomcat webcontext初始化也失敗,應用在掛起狀態,但zkClient線程還是正常的;
- zookeeper服務器重啟,zkClient開始重連,連接上zookeeper服務器;
- zkClient觸發watch的一些代碼,ClassLoader嘗試加載org/apache/zookeeper/proto/SetWatches類,但是發現找不到類,于是拋出異常;
- zkClient捕獲到異常,認為重連失敗,close掉connection,休眠幾秒之后,再次重連;
于是出現了zkClient反復重試連接zookeeper服務器,而且都是秒連秒斷的情況。
總結:
這次排查花了不少時間,有個原因是開始沒有去查看應用的日志,以為應用的是正常的,而且zookeeper.out的輸出日志很多,也有一段時間了。
還有線上的應用比較坑爹,活動已經過期很久了,但是程序還是線上跑,也沒有人管是否出問題了。
所以,主要精力放在各種網絡連接狀態的獲取上。對去查看應用日志比較排斥。
還有一個原因是,問題比較詭異,有點難重現,當發現可以重現時,基本已經發現問題所在了。
排查問題還是要耐心收集信息,再分析判斷。