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
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...