Saltstack 最大打開文件數問題之奇怪的 8192

来源:https://www.cnblogs.com/edisonfish/p/18090269
-Advertisement-
Play Games

哈嘍大家好,我是鹹魚。 今天分享一個在壓測過程中遇到的問題,當時排查這個問題費了我們好大的勁,所以我覺得有必要寫一篇文章來記錄一下。 問題出現 周末在進行壓測的時候,測試和開發的同事反映壓測有問題,請求打到 A 服務上被拒絕了。 我們登錄伺服器查看 A 服務的日誌,發現頻繁地報 Too many o ...


哈嘍大家好,我是鹹魚。

今天分享一個在壓測過程中遇到的問題,當時排查這個問題費了我們好大的勁,所以我覺得有必要寫一篇文章來記錄一下。

問題出現

周末在進行壓測的時候,測試和開發的同事反映壓測有問題,請求打到 A 服務上被拒絕了。

我們登錄伺服器查看 A 服務的日誌,發現頻繁地報 Too many open files 錯誤,可以看到壓測的時候該進程要處理大量的 socket,導致打開的文件描述符數量已經達到了操作系統允許的最大限制,因此無法再打開更多的文件。

java.io.IOException: Too many open files
	...

既然是系統資源相關的問題,我們先 ulimit -n 看一下系統中進程能夠使用的最大文件描述符是多少個:

[root@localhost ~]# ulimit -n 
100000

為了穩妥起見,我們還查看了 /etc/security/limits.conf 文件的內容:

[root@localhost ~]# cat /etc/security/limits.conf
*           soft    nofile          100000
*           hard    nofile          100000

可以看到系統限制進程能夠最多打開 100000 個文件(我們在伺服器初始化的時候設置的值)。但是壓測的量還沒上去,A 服務上的進程打開文件數就超過了 10 萬個嗎?

查看一下這個進程打開了多少個文件:

[root@localhost ~]# cat /proc/<該進程的 PID>/fd | wc -l
8295

我們發現該進程才打開了八千多個文件,遠遠沒有達到系統限制的 100000。

接著看下這個進程的文件描述符數量限制,通過 /proc/<Java 進程的 PID>/limits 文件來查看

[root@localhost ~]# cat /proc/<該進程的 PID>/limits
...
Max open files            8192               8192               files
...

奇怪,按理說每個進程的文件描述符使用限制應該是 100000,但是這裡卻顯示只有 8192,說明系統層面的資源限制在這個進程上沒有生效,而且這個 8192 是怎麼來的,為什麼是 8192 ?

我們重啟了一下這個服務,發現重啟之後該進程的資源限制生效了,Max open files 數量變成了 100000 !

# 重啟服務
[root@localhost ~]# sh spring-boot.sh restart

# 查看該進程的文件描述符數量限制
[root@localhost ~]# cat /proc/<該進程的 PID>/limits
...
Max open files            100000               100000               files
...

定位問題

發現了這個現象之後,我們接著排查了其他的服務,發現服務進程的 Max open files 數量都是 8192,而系統設置的卻是 100000。

如果我們一旦手動重啟服務,進程的 Max open files 數就變成了系統設置的 100000。

我們在初始化伺服器的時候,已經修改了進程的最大打開文件數為 100000,如果配置沒有生效,那也應該是系統的預設值 1024 ,而不是 8192。

就在一籌莫展的時候,我們註意到了一個細微差別:由於線上伺服器較多,平時我們都是通過 Saltstack 來管理服務(包括服務的啟動重啟停止),而今天是在終端上重啟服務的,所以會不會跟 Saltstack 相關?

然後我們為了驗證執行了下麵的步驟:

  1. 找到一臺伺服器,先查看了上面進程的最大打開文件數,發現是 8192。
  2. 手動重啟一下服務,發現進程的最大打開文件數變成 100000
  3. 我們在 salt-master 上遠程重啟這台服務,發現進程的最大打開文件數變成了 8192。

接著我們在 salt-master 上遠程執行 ulimit -a 命令

[root@salt-master ~]# salt <伺服器 ip> cmd.run 'ulimit -a'
...
open files                      (-n) 8192
...

排查到這裡,終於有點柳暗花明的感覺了,我們看一下這台伺服器上 salt-minion 進程的資源限制:

[root@localhost ~]# cat /proc/<salt-minion 進程的 PID>/limits
...
Max open files            8192                 8192                 files 
...

又因為 salt-minion 是通過 systemctl 來管理的,所以我們在這台伺服器上查看 salt-minion 的服務註冊文件:

[root@localhost ~]# cat /usr/lib/systemd/system/salt-minion.service 
[Unit]
...

[Service]
KillMode=process
Type=notify
NotifyAccess=all
LimitNOFILE=8192
ExecStart=/usr/bin/salt-minion

[Install]
...

果然,奇怪的 8192 出現在了這兩處地方!

關於 Linux 下 Ulimit 資源限制

首先,/etc/security/limits.conf 文件中的配置對於通過 PAM 認證登錄的用戶資源限制是有效的。

也就是說,登陸了系統的用戶,無論是互動式登錄還是非互動式登錄,其資源限制都會受到 limits.conf 中的配置影響。

但是,在 CentOS 7/RHEL 7 等系統中,預設採用 Systemd 作為 init 系統,取代了之前的 SysV init,對於 Systemd 啟動的服務(例如使用 systemctl 啟動的服務),limits.conf 中的配置對其資源限制是不生效的。

這是因為 Systemd 會忽略 limits.conf 中的設置,而是使用自己的資源管理機制。

這裡補充一下,在 CenOS 5/6 中,/etc/security/limits.conf/etc/security/limits.d 中的配置文件是為通過PAM登錄的用戶設置資源限制的。這些限制在用戶登錄時由PAM模塊載入並應用(什麼是 PAM ,你可以簡單理解為一般情況登陸了終端都會載入 PAM 模塊),因此僅在用戶會話期間生效。


所以就會出現某進程在機器重啟後資源限制設置與 /etc/security/limits.conflimits.d 下的文件不一致的問題,可能是因為進程是在系統啟動時自動啟動的,而不是通過用戶登錄而啟動的。因此不會受到 PAM 模塊載入的影響。在這種情況下,進程的資源限制可能受到系統級別的預設限制或其他配置文件的影響。

我們對某一臺 CentOS 6 的機器進行重啟後,發現上面設置了開機自啟動的進程的資源限制都發生了變化(變成了系統設置的預設值),一旦我們手動重啟,資源限制則設置成了跟 /etc/security/limits.conf 文件設置的一致

對於一些設置了開機自啟動的進程,如果在機器重啟後保持資源限制不發生變化,可以在進程的啟動腳本裡加上關於資源限制設置的命令,比如說 ulimit -SHn 10000

所以在 Systemd 中,可以通過在服務單元文件中設置 Limit* 選項來控制服務的資源限制,比如限制進程的最大打開文件數 LimitNOFILE 為 8192。

LimitNOFILE=8192

當我們通過 Salt-master 來管理遠程伺服器的時候(伺服器上面往往部署了 Salt-minion),即 Salt-master 發送命令給 Salt-minion 時,通常情況下,Salt-minion 會直接在自身進程中執行相應的操作。

如果是通過 Salt-minion 來啟動一個進程,這個進程則會繼承 Salt-minion 的資源限制配置。

這也就是為什麼通過 salt-minion 管理的進程的最大打開文件數都是 8192,因為 salt-minion 的最大打開文件數就是 8192。

解決問題

既然知道了這是關於 systemd services 的資源限制相關的問題,那就好解決了。

  • 針對所有的 service :

配置 systemd services 的資源限制可以在全局範圍內進行。這些配置文件分別位於 /etc/systemd/system.conf/etc/systemd/user.conf

system.conf 文件適用於系統級實例,而 user.conf 文件適用於用戶級實例。一般建議在 system.conf 中配置服務的資源限制,但如果在 /etc/systemd/system.conf 文件中修改配置,則需要重啟系統才能使更改生效。

此外,還可以通過在 /etc/systemd/system.conf.d//etc/systemd/user.conf.d/ 目錄中放置 .conf 文件進行配置。

需要註意的是,system.conf.d/*.conf 中的配置會覆蓋 system.conf 中的配置。

如果你打算修改所有通過 systemctl 管理的服務進程的資源限制(比如修改最大文件打開數量)

那可以修改/etc/systemd/system.conf

[root@localhost ~]# vim /etc/systemd/system.conf
DefaultLimitNOFILE=100000
  • 針對單個 service:

這次案例的解決方法就是要修改單個 service (即 salt-minion)的資源限制配置。

# 修改 salt-minion 的 service 文件,改成和系統一樣的資源限制配置
[root@localhost ~]# cat /usr/lib/systemd/system/salt-minion.service 
...
[Service]
LimitNOFILE=100000
...

修改完之後別忘了重啟。

[root@localhost ~]# systemctl daemon-reload

[root@localhost ~]# systemctl restart salt-minion.service 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Linq的學習 這裡繼續使用之前文章創建的學生類,首先簡單介紹一下linq的使用。 Student.cs public class Student { public int Id { get; set; } public int ClassId { get; set; } public string ...
  • 前言 從.Net Core 開始,.Net 平臺內置了一個輕量,易用的 IOC 的框架,供我們在應用程式中使用,社區內還有很多強大的第三方的依賴註入框架如: Autofac DryIOC Grace LightInject Lamar Stashbox Simple Injector 內置的依賴註入 ...
  • 新建項目 在建項目的時候要註意,選擇Windows 窗體應用(.NET Framework)或者wpf項目,然後打開 安裝包 在解決方案資源管理器中,選擇剛纔的項目名,滑鼠右鍵找到並打開管理NuGet包,然後在瀏覽選項卡裡,輸入一個Costura.Fody並查找,有就點安裝,安裝前需要註意選擇支持的 ...
  • TagProvider [LogProperties] 與 [LogPropertyIgnore] 如果用在DTO不存在任何問題,如果用在Domain實體上,可能有點混亂。 您可能不希望因日誌記錄問題而使您的域模型變得混亂。對於這種情況,可以使用[TagProvider]屬性來豐富日誌。 我們仍然使 ...
  • 概述:本指南詳細解釋了在C#中如何在創建控制項的線程以外的線程中訪問GUI。基礎功能使用`Control.Invoke`(WinForms)或`Dispatcher.Invoke`(WPF),高級功能則利用`SynchronizationContext`實現線程間通信,確保代碼清晰可讀。 在C#中,要 ...
  • 概述:.NET應用程式以管理員身份運行的方法包括修改清單文件、項目文件,或在運行時動態請求管理員許可權。清單文件和項目文件通過聲明UAC請求,而動態請求管理員許可權則在程式啟動時檢查並重新啟動。選擇適當的方法取決於項目需求和配置。 在.NET應用程式中強制以管理員身份運行,可以通過清單文件、項目文件或者 ...
  • Nginx的location匹配順序是Nginx配置中非常核心且重要的概念,它決定了Nginx如何處理進入伺服器的請求。理解location匹配順序不僅有助於優化Nginx的性能,還能確保網站或應用的正確運行。下麵將詳細闡述Nginx的location匹配順序,並通過實例加以說明。 Nginx lo ...
  • 來自chatGPT 在CentOS 7.9系統上安裝Docker,你可以遵循以下步驟: 更新你的系統:首先,確保你的系統是最新的。這可以通過運行下麵的命令來實現: sudo yum update 安裝必要的包:為了使得yum源支持https,你需要安裝幾個必要的包: sudo yum install ...
一周排行
    -Advertisement-
    Play Games
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...