嵌入式C語言開發(fā):文件描述符(fd)泄漏排查(經(jīng)驗分享)
大家好,今天給大家介紹文件描述符(fd)泄漏排查,文章末尾附有本畢業(yè)設(shè)計的論文和源碼的獲取方式,可進群免費領(lǐng)取。
生產(chǎn)多次遇到文件描述符(fd)泄露相關(guān)的問題, 文件描述符泄漏一般引起
的現(xiàn)象是文件句柄數(shù)(封面圖)/tcp alloc(上圖)增長。文章分為兩部分介紹文件描述符相關(guān)內(nèi)容,第一部分介紹文件描述基礎(chǔ)知識,第二部分通過實際案例進行剖析。
一. 文件描述符相關(guān)基礎(chǔ)知識
-
什么是文件描述符?
內(nèi)核利用文件描述符來訪問文件, 打開現(xiàn)存文件或新建文件(建立)時,內(nèi)核會返回一個文件描述符,讀寫文件也需要使用文件描述符來指定待讀寫的文件。所有執(zhí)行I/O操作(包括網(wǎng)絡(luò)socket操作)的系統(tǒng)調(diào)用都通過文件描述符 -
最大文件描述符介紹系統(tǒng)最大文件描述符限制
sysctl -a | grep fs.file-max (查看系統(tǒng)最大描述符)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代表所有用戶,支持具體用戶(優(yōu)先級高,不受影響)。文件修改即生效,退出
或打開新終端執(zhí)行ulimit -n即看到修改效果具體某個進程(PID)最大描述符通過cat /proc/PID/limits | grep “Max open files”Limit Soft Limit Hard Limit UnitsMax open files 65536 65536 files進程最大描述符受限與系統(tǒng)/用戶級,以及進程本身相關(guān)代碼程序限制,比如下面Golang代碼將進程打開的最大描述符限制為10var rLimit syscall.RlimitrLimit.Cur = 10if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil {panic(err)}
二. 文件描述符泄漏的實際案例
某個周末,ops同學在運維群反饋某核心業(yè)務(wù)應(yīng)用文件描述符以及tcp alloc非常高,導致服務(wù)不可用(這塊監(jiān)控不到位)。業(yè)務(wù)架構(gòu)同學為了排查相關(guān)問題具體原因保留了一臺問題服務(wù),當然咯,閑著無事,參與線上故障排查。從監(jiān)控圖看到文件描述符不斷/tcp alloc 不斷增長
- 首先考慮是否由于Socket連接建立以后未close導致,這類也是最容易排查,netstat顯示的tcp連接數(shù)正常
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
- ss -s 查看大量處于closed 狀態(tài)
- 通過lsof 查看tomcat 進程(進程4730)打開的文件描述符相關(guān)詳細信息,lsof -p 4730。大量Prtocol:TCP異常描述符如下圖所示:
-
通過lsof 相關(guān)信息我們找不出具體由于某原因?qū)е碌模覀兺ㄟ^strace查看系統(tǒng)調(diào)用, 查看fd泄漏的具體原因 (抓取5分鐘)
strace -f -p 4730 -T -tt -o /home/futi/strace_4730.log-tt 在每行輸出的前面,顯示毫秒級別的時間-T 顯示每次系統(tǒng)調(diào)用所花費的時間-v 對于某些相關(guān)調(diào)用,把完整的環(huán)境變量,文件stat結(jié)構(gòu)等打出來。-f 跟蹤目標進程,以及目標進程創(chuàng)建的所有子進程-e 控制要跟蹤的事件和跟蹤行為,比如指定要跟蹤的系統(tǒng)調(diào)用名稱-o 把strace的輸出單獨寫到指定的文件-s 當系統(tǒng)調(diào)用的某個參數(shù)是字符串時,最多輸出指定長度的內(nèi)容,默認是32個字節(jié)-p 指定要跟蹤的進程pid, 要同時跟蹤多個pid, 重復多次-p選項即可。tomcate多線程應(yīng)用,我們需要追蹤子進程運行情況,所以-f,其它參數(shù)大家看解析應(yīng)該可以理解
- /home/futi/strace_4730.log,找到strace抓取這段時間內(nèi)最近泄漏的fd進行分析,通過lsof -d 49959 ,可以看到出現(xiàn)Prtocol:TCP異常情況。下面截一小部分內(nèi)容前面有大量對fd為49959打開,關(guān)閉等操作。但從4783線程操作這個fd以后strace抓取的內(nèi)容未有再使用49959這個fd,且fd 不斷增大,有使用大于49959的fd,所以我們可以斷定是這個fd 在這塊出了問題。
- 從上面似乎我們找不到根本原因,《Linux環(huán)境編程:從應(yīng)用到內(nèi)核》有這么一段:在多線程下,可能會在fcntl調(diào)用前,就已經(jīng)fork出子進程。從這點出發(fā)我們查看tomcat線程ID為4783在執(zhí)行fcntl前做了哪些操作,可以看出4783線程寫入了一條ERROR日志lsof -d
369 可以找到fd為369對應(yīng)打開的文件:
/data/applogs/cat/cat_20190722.log查看具體log 如下,由于連接Cat失敗導致fd泄漏(由于cat上線很久了,忽略了查看cat 日志)
完整代碼可進群免費領(lǐng)取!!!
嵌入式物聯(lián)網(wǎng)的學習之路非常漫長,不少人因為學習路線不對或者學習內(nèi)容不夠?qū)I(yè)而錯失高薪offer。不過別擔心,我為大家整理了一份150多G的學習資源,基本上涵蓋了嵌入式物聯(lián)網(wǎng)學習的所有內(nèi)容。點擊下方鏈接,0元領(lǐng)取學習資源,讓你的學習之路更加順暢!記得點贊、關(guān)注、收藏、轉(zhuǎn)發(fā)哦!
- 贊