色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Too many open files錯誤導致服務器死循環

Linux閱碼場 ? 來源:卯時卯刻 ? 2023-05-23 09:08 ? 次閱讀

0x01 前言

在服務器編程中,經常會遇到 Too many open files 這個報錯,而且這個報錯如果處理不好,很有可能會導致服務器死循環。

0x02 示例代碼

6eb5ae6a-f8fd-11ed-90ce-dac502259ad0.png

以上是我用rust寫的一個非常簡單的tcp服務器,它的主要邏輯是,先創建一個listener,然后再在循環里不斷調用listener.accept接收tcp連接,如果接收成功,就調用handle_client處理這個連接,如果接收失敗,就打印一行錯誤日志。

handle_client里的邏輯也非常簡單,就是等待客戶端關閉連接,或等待其發送任意數據,當這兩種情況發生時,handle_client就會直接關閉這個連接。

當然,如果在等待期間報錯了,handle_client也會打印一行錯誤日志。

下面我們就會使用這段程序,來演示服務器死循環的情況,這段程序不必非要用rust編寫,用其他語言也都可以。

0x03 動手演示

先啟動該服務器:

6edcb6b8-f8fd-11ed-90ce-dac502259ad0.png

由上圖可見,該服務器的進程id是312004,監聽地址是0.0.0.0:9999。

再查看下該服務器已打開的文件數:

6f0a1270-f8fd-11ed-90ce-dac502259ad0.png

一共是10個,主要包括標準輸入輸出、epoll、及一些socket。

再查看下該服務器進程最多可打開的文件數:

6f3a0c50-f8fd-11ed-90ce-dac502259ad0.png

看選中行,Soft Limit那一列,其表示該進程最多可用的文件描述符數量為1024個,即最多可同時打開的文件數為1024個。

我們把它改小一點,方便后續測試:

6f53f6c4-f8fd-11ed-90ce-dac502259ad0.png

上圖中,先使用prlimit命令將該服務器進程的Max open files數改成12,然后再用cat命令確認下該改動已生效。

至此,我們已經設置好該服務器進程最多可用的文件描述符數量為12,其當前已用的文件描述符數量為10,所以該服務器最多還可以再接收2個tcp連接。

我們用 `ncat localhost 9999` 命令建立連接試一下,當然你也可以用telnet, nc等其他命令,只要能建立tcp連接就行:

6f82eede-f8fd-11ed-90ce-dac502259ad0.png

由上圖服務器日志可見,該tcp連接已建立成功。

再看下當前服務器已使用的文件描述符數量:

6fc1c30c-f8fd-11ed-90ce-dac502259ad0.png

由上圖可見,新建socket使用的文件描述符為10,當前服務器進程已使用11個文件描述符,到目前為止一切正常。

用同樣的命令再建立一個tcp連接,這次應該也能連接成功,不過會有一些有意思的事情發生:

6ff862fe-f8fd-11ed-90ce-dac502259ad0.png

首先看上圖中最后一行info日志,它表示第二次tcp連接也建立成功了,如果此時去看文件描述符數量,也正好是12。

不過此次連接建立也導致不斷的error日志輸出,該服務器死循環了。

但此時,如果我們關閉第二次ncat命令建立的tcp連接,服務器又不會一直輸出error日志了,它又會恢復到正常狀態:

707b880a-f8fd-11ed-90ce-dac502259ad0.png

看上圖中的最后一條info日志,它表示第二個tcp連接正常關閉了,且當前已建立的連接數量是1。

此時,如果我們去看文件描述符數量,其也變成了11,這里就不再截圖了,有興趣的可以自己動手試下。

0x04 為什么會出現死循環?

首先,在linux的世界里,一切皆文件,這里就包括socket。

其次,linux為保證系統的整體性安全,為每個進程限制了其最大可使用的文件描述符數量,即最大可打開的文件數,這個數量就是上面我們用 `cat /proc/$(pidof too-many-open-files)/limits` 命令輸出的Max open files行,Soft Limit列對應的值,該值是可以通過各種方式修改的,在我的系統上,該值默認為1024。

接著,我們啟動了服務器,然后通過 `l /proc/$(pidof too-many-open-files)/fd/` 命令查看該服務器已使用的文件描述符數量,其為10。

之后,我們用prlimit命令將該服務器進程最大可使用的文件描述符數量改成了12,這樣該服務器就還只剩兩個文件描述符可用。

再之后,我們用ncat命令建立了兩個tcp連接,在服務器端的循環里,accept接收到這兩個連接并進行處理,此時該服務器進程消耗完了最后兩個可用的文件描述符。

接下來,服務器代碼進入下一次循環,繼續調用accept嘗試接收新的連接,問題的關鍵點也就出現在了這里。

accept是個系統調用,我們看下其對應的內核實現:

70baa9a4-f8fd-11ed-90ce-dac502259ad0.png

這個是accept系統調用的入口函數,沿著函數調用,可找到以下代碼:

70df7248-f8fd-11ed-90ce-dac502259ad0.png

由上圖可見,在真正的do_accept之前,會先調用get_unused_fd_flags找一個還未被使用的文件描述符,如果尋找時報錯了,即newfd < 0,則直接返回該錯誤碼給用戶層,如果找到了一個可用的文件描述符,則開始執行真正的accept操作。

繼續看get_unused_fd_flags函數:

712824f2-f8fd-11ed-90ce-dac502259ad0.png

它在調用其他函數之前,會通過 rlimit(RLIMIT_NOFILE) 獲取當前進程最大可使用的文件描述符數量,即我們上面通過prlitmit命令設置的12。

繼續往下看,我們會找到以下代碼:

7147c500-f8fd-11ed-90ce-dac502259ad0.png

該函數的目的是分配一個文件描述符,即fd,圖中選中行之前是找到一個還未被使用的fd,然后判斷該 fd 是否 >= end,如果是,則goto到out,進而return error,而這個error就是EMFILE。

那end值是什么呢?它就是上面用 rlimit(RLIMIT_NOFILE) 獲取的當前進程最大可用的文件描述符數。

結合上面的例子我們知道,當服務器接收完兩個tcp連接后,其最大可使用的12個文件描述符已全部被用完,當其循環到下一次accept系統調用后,會最終進入到上圖這個函數,這次新分配的fd值一定是12(因為fd值從0開始的,所以fd值為12表示第13個文件描述符),而我們又限制了該進程最大可用12個文件描述符,即我們限制了end值為12,所以在上圖選中行進行判斷時,fd 一定是 >= end 的,所以,該函數一定會返回EMFILE這個錯誤碼。

而EMFILE是什么呢?

7191e536-f8fd-11ed-90ce-dac502259ad0.png

它就是我們在運行測試程序時看到的 Too many open files 這個錯誤。

示例程序調用accept收到這個錯誤碼后,會打印一行error日志,然后繼續循環調用accept,然后繼續報錯,就這樣,服務器就在accept這里發生了死循環。

0x05 這個問題如何處理?

因為 too many open files 是個臨時性錯誤,當進程中的其他地方關閉了一些文件,或者管理人員調高了該進程的 max open files值,accept就不會再報 EMFILE 錯誤,也就不會再死循環了。

所以其處理方法也很簡單,就是在accept發生錯誤時,sleep一段時間,這樣既防止了cpu 100%的發生,也給進程時間來調整已用及最大的文件描述符數。

0x06 用epoll也會有這個問題嗎?

會有,epoll只是個通知機制,當epoll檢測到有連接可被接收時,還是會通過accept來接收這個連接。

不過這里分成兩種情況。

當使用epoll的edge-triggered模式時,正確寫法是要一直循環調用accept接收連接,直到其返回 EAGAIN 或 EWOULDBLOCK 錯誤碼,表示已經沒有連接可接收了,這時才能退出accept循環,但如果在這之前accept返回了 too many open files 這個錯誤,就會發生死循環了。

當使用epoll的level-triggered模式時,可以不必一直循環調用accept直到其返回EAGAIN 或 EWOULDBLOCK,可以提前退出,但如果操作系統里還有建立好的連接等待被接收,epoll還是會一直通知應用層,告知其要調用accept接收這些連接,如果此時文件描述符沒有了,accept還是會一直報 too many open files 錯誤,最終還是進入到了死循環。

0x07 Go是如何處理的?

下面我們看下go內置的http服務器,是如何處理這個問題的:

71c64876-f8fd-11ed-90ce-dac502259ad0.png

當accept返回err后,其會通過ne.Temporary()來檢查該err是否是臨時性錯誤,如果是,則會根據一定的規則,sleep一段時間。

這里,臨時性錯誤就包括 EMFILE,即too many open files錯誤:

7203ec08-f8fd-11ed-90ce-dac502259ad0.png

我們也可以寫個簡單的例子測試下:

721b8264-f8fd-11ed-90ce-dac502259ad0.png

按照之前的方式,讓其觸發 too many open files 這個錯誤:

7244e2d0-f8fd-11ed-90ce-dac502259ad0.png

由圖可見,和我們上面分析的一樣,其也陷入了死循環,但是它用sleep的方式,防止cpu使用率100%。

0x08 Redis是如何處理的?

下面我們看下redis是如何處理這個問題的:

727fddd6-f8fd-11ed-90ce-dac502259ad0.png

當anetTcpAccept返回 too many open files 錯誤時,它只打印了一行錯誤日志,就直接return了。

不過因為redis使用的是level-triggered模式的epoll,所以雖然這里直接return了,但因為底層的連接沒接收出來,epoll一直會調用這個函數,然后一直報錯,進而死循環。

實驗下:

72b90a48-f8fd-11ed-90ce-dac502259ad0.png

可以看到,其一直在輸出這個錯誤。





審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • TCP
    TCP
    +關注

    關注

    8

    文章

    1395

    瀏覽量

    80223
  • TELNET
    +關注

    關注

    0

    文章

    17

    瀏覽量

    10895
  • Rust
    +關注

    關注

    1

    文章

    233

    瀏覽量

    6914

原文標題:Too many open files 錯誤導致服務器死循環

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 0人收藏

    評論

    相關推薦
    熱點推薦

    獨立看門狗檢測及如何解決軟件錯誤導致故障

    其用于檢測和解決由軟件錯誤導致的故障,當計數達到設定的超時時間值時會產生系統復位。
    的頭像 發表于 01-23 09:14 ?1.2w次閱讀
    獨立看門狗檢測及如何解決軟件<b class='flag-5'>錯誤導致</b>故障

    編譯錯誤too many global/static 'bit' variables

    用的CodeVisionAVR編譯,編譯出錯,很多都是說too many global/static 'bit' variablesError: D:\AVRproject\2014\test
    發表于 04-04 22:37

    too many jtag devices in chain

    用keil下載程序時,出現too many jtag devices in chain,哪位大神知道怎么解決,十分感謝!
    發表于 01-20 13:46

    什么是服務器500錯誤

    500報錯:被稱為http500服務器內部錯誤,從名稱上可以理解為服務器問題導致錯誤。一般給站長展現出的問題分為兩種情況,一是
    發表于 07-08 09:38

    為什么單片機的主程序是死循環

    任何一個可用程序都必然是死循環程序,這不僅僅是指單片機程序。因為任何微處理系統一旦開機,系統都在處理內部事件和外設響應,這個過程是一個循環過程,除非關機才能結束這個死循環程序。因此,
    發表于 07-15 17:38 ?5687次閱讀

    單片機的死循環有什么作用

    單片機是可編程器件,在使用時需要編寫滿足需求的程序。其C語言程序在各個端口、配置初始化完成后,會進入一個死循環,一般用while(1){;}的形式。初始化完成后,單片機就在死循環內一遍又一遍的執行程序邏輯。復位后,就從頭開始,初始化完成后,再次進入
    發表于 08-09 17:01 ?6029次閱讀
    單片機的<b class='flag-5'>死循環</b>有什么作用

    如何避免Xil_Assert系列宏導致死循環的情況

    原文標題:【工程師分享】避免Xil_Assert系列宏導致死循環 文章出處:【微信公眾號:FPGA開發圈】歡迎添加關注!文章轉載請注明出處。
    的頭像 發表于 12-02 16:20 ?4505次閱讀
    如何避免Xil_Assert系列宏<b class='flag-5'>導致</b>的<b class='flag-5'>死循環</b>的情況

    STM32片內FLASH燒寫錯誤導致ST-li

    STM32片內FLASH燒寫錯誤導致ST-li
    發表于 12-02 18:06 ?7次下載
    STM32片內FLASH燒寫<b class='flag-5'>錯誤導致</b>ST-li

    IAR中出現“ the file is too large to open in the editor”

    IAR中出現“ the file is too large to open in the editor”出現此錯誤是,先在在工程設置“Options”----》“General Options
    發表于 12-03 11:06 ?0次下載
    IAR中出現“ the file is <b class='flag-5'>too</b> large to <b class='flag-5'>open</b> in the editor”

    Too many open files錯誤導致服務器死循環

    0x01 前言 在服務器編程中,經常會遇到 Too many open files 這個報錯,而且這個報錯如果處理不好,很有可能會
    的頭像 發表于 05-23 09:09 ?3560次閱讀
    <b class='flag-5'>Too</b> <b class='flag-5'>many</b> <b class='flag-5'>open</b> <b class='flag-5'>files</b><b class='flag-5'>錯誤導致</b><b class='flag-5'>服務器</b><b class='flag-5'>死循環</b>

    為什么HashMap會產生死循環呢?

    死循環問題發生在 JDK 1.7 版本中,造成這個問題主要是由于 HashMap 自身的運行機制,加上并發操作,從而導致死循環
    的頭像 發表于 12-21 09:06 ?1158次閱讀
    為什么HashMap會產生<b class='flag-5'>死循環</b>呢?

    應用程序中的服務器錯誤怎么解決?

    在使用應用程序時,可能會遇到服務器錯誤的問題。這種錯誤通常會導致應用程序無法正常運行 ,給用戶帶來不便。下面將介紹應用程序中的服務器
    的頭像 發表于 03-12 15:13 ?7218次閱讀

    服務器數據恢復—SAN環境下LUN映射錯誤導致寫操作互斥失敗的數據恢復案例

    服務器數據恢復環境: SAN環境下一臺存儲設備中有一組由6塊硬盤組建的RAID6磁盤陣列,劃分若干LUN,MAP到不同業務的SOLARIS操作系統服務器上。 服務器故障: 用戶新增了一臺
    的頭像 發表于 09-26 16:31 ?388次閱讀

    服務器錯誤是怎么回事

    服務器錯誤通常指的是在訪問網站或應用程序時,由于服務器端的問題導致無法正常處理請求。主機測評小編為您整理發布一些常見的服務器
    的頭像 發表于 11-04 11:11 ?865次閱讀

    服務器數據恢復—如何預防服務器故障與恢復服務器數據!

    服務器常見故障: 硬件故障:磁盤損壞、電池故障等。 軟件問題:操作系統崩潰、未知的程序運行錯誤等。 病毒破壞:勒索病毒加密、刪除服務器數據等。 不可控力量;服務器浸水、火燒、機
    的頭像 發表于 03-11 12:36 ?225次閱讀
    主站蜘蛛池模板: 添加一点爱与你电视剧免费观看 | 热热久久超碰精品中文字幕 | 国产呦精品一区二区三区下载 | 亚洲AV久久无码精品九九软件 | 嫩草影院未满十八岁禁止入内 | 人与禽交3d动漫羞羞动漫 | 我就去色色 | 国产精品久久久久久久久爆乳 | 一手揉着乳头一手模仿抽插视频 | 毛片免费观看视频 | 天天射天天爱天天干 | 亚洲精品123区 | 精品无码人妻一区二区免费AV | 国产色欲一区二区精品久久呦 | 国内精品久久久久影院男同志 | 色婷婷国产精品视频一区二区 | 日本妞欧洲 | 亚洲 欧美 中文字幕 在线 | 蜜桃视频一区二区 | 亲爱的妈妈6韩国电影免费观看 | 色狠狠AV老熟女 | 国产日韩欧美三级 | 无人视频在线观看免费播放影院 | 男女又黄又刺激B片免费网站 | 国产真实乱对白精彩 | 久久亚洲AV成人无码动态图 | 欧美国产精品主播一区 | 日韩精品在线观看免费 | 久久青草免费91线频观看站街 | 久久亚洲精品专区蓝色区 | 蝴蝶中文娱乐 | 日本伦理片 中文字幕 | 国产成人在线视频 | 国产精品久久一区二区三区蜜桃 | 日韩丰满少妇无码内射 | 俄罗斯15一16处交 | gv手机在线观看 | 十八禁肉动漫无修在线播放 | 久久综合中文字幕无码 | 秋霞伦理高清视频在线 | 91精品国产色综合久久不 |

    電子發燒友

    中國電子工程師最喜歡的網站

    • 2931785位工程師會員交流學習
    • 獲取您個性化的科技前沿技術信息
    • 參加活動獲取豐厚的禮品