現象:一個后台進程在跑了1000多分鍾后,不再寫日志,同時進程還有每分鍾發送的一個網絡請求,在服務端也沒看到日志。
排查方式:首先懷疑是進程hang住了,但是通過gdb attach到進程,再打斷點到網絡請求函數,發現仍然是正常的每分鍾進入一次,但是會報server connect failed錯誤。說明進程仍在正常執行,只是寫日志和網絡請求都是失敗了。
因此懷疑是進程的fd滿了。用ps命令查看進程id,然后執行ll /proc/12260/fd打印進程的fd信息,發現socket數量達到了1006多個,再加上一些管道,剛好是1024個。
再用ulimit -a查看系統的進程最大fd數open files的值,正好為1024,說明是因為進程的fd滿了,導致寫日志和發送網絡請求都失敗了。
接下來就是排查出現fd泄露的位置。通過lsof -p 12260查看進程占用socket fd的類型,發現是UDP類型。在程序中,創建UDP套接字的只有一個位置,是通過socket+ioctl獲取本機ip的函數,確認了該函數確實沒有close掉fd,並且該函數也是一分鍾調用一次。
結論:系統設置了進程最大的fd數量,創建socket會消耗fd,並且當fd到達最大值時無法再創建。使用linux原生的socket函數時需要記得close fd,否則會出現fd泄露問題。