嵌入式C語言開發:文件描述符(fd)泄漏排查(經驗分享)

大家好,今天給大家介紹文件描述符(fd)泄漏排查,文章末尾附有本畢業設計的論文和源碼的獲取方式,可進群免費領取。

生產多次遇到文件描述符(fd)泄露相關的問題, 文件描述符泄漏一般引起
的現象是文件句柄數(封面圖)/tcp alloc(上圖)增長。文章分為兩部分介紹文件描述符相關內容,第一部分介紹文件描述基礎知識,第二部分通過實際案例進行剖析。

一. 文件描述符相關基礎知識

  1. 什么是文件描述符?
    內核利用文件描述符來訪問文件, 打開現存文件或新建文件(建立)時,內核會返回一個文件描述符,讀寫文件也需要使用文件描述符來指定待讀寫的文件。所有執行I/O操作(包括網絡socket操作)的系統調用都通過文件描述符
  2. 最大文件描述符介紹系統最大文件描述符限制
    sysctl -a | grep fs.file-max (查看系統最大描述符)echo “fs.file-max=1610270” >> /etc/sysctl.conf(修改最大描述符)sysctl -p(立即生效)用戶級最大文件描述限制ulimit -n (查看用戶最大描述符)echo “* hard nofile 65535” >> /etc/security/limits.confecho “* soft nofile 65535” >> /etc/security/limits.conf
    代表所有用戶,支持具體用戶(優先級高,不受影響)。文件修改即生效,退出
    或打開新終端執行ulimit -n即看到修改效果具體某個進程(PID)最大描述符通過cat /proc/PID/limits | grep “Max open files”Limit Soft Limit Hard Limit UnitsMax open files 65536 65536 files進程最大描述符受限與系統/用戶級,以及進程本身相關代碼程序限制,比如下面Golang代碼將進程打開的最大描述符限制為10var rLimit syscall.RlimitrLimit.Cur = 10if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil {panic(err)}

二. 文件描述符泄漏的實際案例

某個周末,ops同學在運維群反饋某核心業務應用文件描述符以及tcp alloc非常高,導致服務不可用(這塊監控不到位)。業務架構同學為了排查相關問題具體原因保留了一臺問題服務,當然咯,閑著無事,參與線上故障排查。從監控圖看到文件描述符不斷/tcp alloc 不斷增長

  1. 首先考慮是否由于Socket連接建立以后未close導致,這類也是最容易排查,netstat顯示的tcp連接數正常
 netstat -tan|awk '$1~/tcp/{print $NF}'|sort|uniq -c|sort -nr 156 TIME_WAIT 141 FIN_WAIT2 80 ESTABLISHED 10 LISTEN 3 CLOSE_WAIT 2 LAST_ACK


  1. ss -s 查看大量處于closed 狀態


  1. 通過lsof 查看tomcat 進程(進程4730)打開的文件描述符相關詳細信息,lsof -p 4730。大量Prtocol:TCP異常描述符如下圖所示:
  1. 通過lsof 相關信息我們找不出具體由于某原因導致的,我們通過strace查看系統調用, 查看fd泄漏的具體原因 (抓取5分鐘)
    strace -f -p 4730 -T -tt -o /home/futi/strace_4730.log-tt 在每行輸出的前面,顯示毫秒級別的時間-T 顯示每次系統調用所花費的時間-v 對于某些相關調用,把完整的環境變量,文件stat結構等打出來。-f 跟蹤目標進程,以及目標進程創建的所有子進程-e 控制要跟蹤的事件和跟蹤行為,比如指定要跟蹤的系統調用名稱-o 把strace的輸出單獨寫到指定的文件-s 當系統調用的某個參數是字符串時,最多輸出指定長度的內容,默認是32個字節-p 指定要跟蹤的進程pid, 要同時跟蹤多個pid, 重復多次-p選項即可。tomcate多線程應用,我們需要追蹤子進程運行情況,所以-f,其它參數大家看解析應該可以理解


  1. /home/futi/strace_4730.log,找到strace抓取這段時間內最近泄漏的fd進行分析,通過lsof -d 49959 ,可以看到出現Prtocol:TCP異常情況。下面截一小部分內容前面有大量對fd為49959打開,關閉等操作。但從4783線程操作這個fd以后strace抓取的內容未有再使用49959這個fd,且fd 不斷增大,有使用大于49959的fd,所以我們可以斷定是這個fd 在這塊出了問題。
  1. 從上面似乎我們找不到根本原因,《Linux環境編程:從應用到內核》有這么一段:在多線程下,可能會在fcntl調用前,就已經fork出子進程。從這點出發我們查看tomcat線程ID為4783在執行fcntl前做了哪些操作,可以看出4783線程寫入了一條ERROR日志lsof -d

369 可以找到fd為369對應打開的文件:
/data/applogs/cat/cat_20190722.log查看具體log 如下,由于連接Cat失敗導致fd泄漏(由于cat上線很久了,忽略了查看cat 日志)

完整代碼可進群免費領取!!!

嵌入式物聯網的學習之路非常漫長,不少人因為學習路線不對或者學習內容不夠專業而錯失高薪offer。不過別擔心,我為大家整理了一份150多G的學習資源,基本上涵蓋了嵌入式物聯網學習的所有內容。點擊下方鏈接,0元領取學習資源,讓你的學習之路更加順暢!記得點贊、關注、收藏、轉發哦!

點擊這里找小助理0元領取:

the end

評論(0)