netstat統計的tcp串連數與?proc?pid?fd下socket類型fd數量不一致的分析

來源:互聯網
上載者:User

標籤:ring   div   apt-get   rem   row   jvm   通知   tar   lan   

最近,線上一個應用,發現socket數緩慢增長,並且不回收,超過警告線之後,被營運監控自動重啟了。

首先到zabbix上觀察JVM記錄,發現JVM-Perm space最近兩周沒有資料,猜測是程式從JDK7切換到JDK8了。問過開發人員之後,程式已經很久沒有重啟了,最近才重新發布的。而在這期間,線上的Java運行環境已經從JDK7升級到JDK8了。

因為jdk8裡沒有Perm space了,換成了Metaspace。

###netstat
到線上伺服器上,用netstat來統計進程的connection數量。

1 netstat -antp | grep pid | wc -l

發現比zabbix上的統計socket數量要少100多,netstat統計只有100多,而zabbix上監控資料有300多。

於是到/proc/$pid/fd下統計socket類型的fd數量:

12 cd /proc/$pid/fdls -al | grep socket | wc -l

探索資料和zabbix上的資料一致。

###netstat是怎麼統計的

####下載netstat的原始碼
http://unix.stackexchange.com/questions/21503/source-code-of-netstat

1 apt-get source net-tools

從netstat的代碼裡,大概可以看到是讀取/proc/net/tcp裡面的資料來擷取統計資訊的。

####java和c版的簡單netstat的實現
java版的

http://www.cs.earlham.edu/~jeremiah/LinuxSocket.java

C版的:

http://www.netmite.com/android/mydroid/system/core/toolbox/netstat.c

####用starce跟蹤netstat

1 strace netstat -antp

可以發現netstat把/proc 下的很多資料都讀取出來了。於是大致可以知道netstat是把/proc/pid/fd 下面的資料和/proc/net/下面的資料匯總,對照得到統計結果的。

####哪些socket會沒有被netstat統計到?
又在網上找了下,發現這裡有說到socket如果建立了,沒有bind或者connect,就不會被netstat統計到。

http://serverfault.com/questions/153983/sockets-found-by-lsof-but-not-by-netstat

實際上,也就是如果socket建立了,沒有被使用,那麼就只會在/proc/pid/fd下面有,而不會在/proc/net/下面有相關資料。

簡單測試了下,的確是這樣:

1 int socket = socket(PF_INET,SOCK_STREAM,0); //不使用

另外,即使socket是使用過的,如果執行shutdown後,剛開始裡,用netstat可以統計到socket的狀態是FIN_WAIT1。過一段時間,netstat統計不到socket的資訊的,但是在/proc/pid/fd下,還是可以找到。

中間的時候,自己寫了個程式,把/proc/pid/fd 下的inode和/proc/net/下面的資料比較,發現的確有些socket的inode不會出現在/proc/net/下。

####用lsof查看
用lsof查看socket inode:

###觸發GC,回收socket
於是嘗試觸發GC,看下socket會不會被回收:

1 jmap -histo:live <pid>

結果,發現socket都被回收了。

再看下AbstractPlainSocketImpl的finalize方法:

123456 /** * Cleans up if the user forgets to close it. */protected void finalize() throws IOException { close();}

可以看到socket是會在GC時,被close掉的。
寫個程式來測試下:

123456789 public class TestServer {public static void main(String[] args) throws IOException, InterruptedException {for(int i = 0; i < 10; ++i){ServerSocket socket = new ServerSocket(i + 10000);System.err.println(socket);}System.in.read();}}

先執行,查看/proc/pid/fd,可以發現有相關的socket fd,再觸發GC,可以發現socket被回收掉了。

##其它的東東

####anon_inode:[eventpoll]

1 ls -al /proc/pid/fd

可以看到有像這樣的輸出:

1 661 -> anon_inode:[eventpoll]

這種類型的inode,是epoll建立的。

再扯遠一點,linux下java裡的selector實現是epoll結合一個pipe來實現事件通知功能的。所以在NIO程式裡,會有anon_inode:[eventpoll]和pipe類型的fd。

####為什麼tail -f /proc/$pid/fd/1 不能讀取到stdout的資料
http://unix.stackexchange.com/questions/152773/why-cant-i-tail-f-proc-pid-fd-1

##總結
原因是jdk升級之後,GC的工作方式有變化,FullGC執行的時間變長了,導致有些閒置socket沒有被回收。

本文比較亂,記錄下一些工具和技巧。

netstat統計的tcp串連數與?proc?pid?fd下socket類型fd數量不一致的分析

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.