1. 程式人生 > >limit資源限制ulimit 詳解

limit資源限制ulimit 詳解

       系統性能一直是一個受關注的話題,如何通過最簡單的設定來實現最有效的效能調優,如何在有限資源的條件下保證程式的運作,ulimit 是我們在處理這些問題時,經常使用的一種簡單手段。ulimit 是一種 Linux 系統的內鍵功能,它具有一套引數集,用於為由它生成的 shell程序及其子程序的資源使用設定限制。

命令總結:

檢視系統使用者所有限制值:ulimit -a

設定使用者open files(使用者可以開啟檔案的最大數目):ulimit -n 4096。執行該命令非root使用者只能設定到4096。想要設定到8192需要sudo許可權或者root使用者。

檢視當前系統開啟的檔案數量:

lsof | wc -l  
檢視當前程序的開啟檔案數量:lsof -p pid | wc -l      (lsof -p 1234 | wc -l  )

檢視當前程序的最大可以開啟的檔案數:cat /proc/PID/limits  (如果通過ulimit -n 設定或者修改/etc/security/limits.conf,看看程序是否生效)  

檢視系統總限制開啟檔案的最大數量:cat /proc/sys/fs/file-max

lsof只能以root許可權執行。在終端下輸入lsof即可顯示系統開啟的檔案,因為 lsof 需要訪問核心記憶體和各種檔案,所以必須以 root 使用者的身份執行它才能夠充分地發揮其功能。

1、ulimit的功能

假設有這樣一種情況,當一臺 linux 主機上同時登陸了 10 個人,在系統資源無限制的情況下,這 10 個使用者同時打開了 500 個文件,而假設每個文件的大小有 10M,這時系統的記憶體資源就會受到巨大的挑戰。

    而實際應用的環境要比這種假設複雜的多,例如在一個嵌入式開發環境中,各方面的資源都是非常緊缺的,對於開啟檔案描述符的數量,分配堆疊的大小,CPU 時間,虛擬記憶體大小等等,都有非常嚴格的要求。資源的合理限制和分配,不僅僅是保證系統可用性的必要條件,也與系統上軟體執行的效能有著密不可分的聯絡。這時,ulimit 可以起到很大的作用,它是一種簡單並且有效的實現資源限制的方式。

    ulimit 用於限制 shell 啟動程序所佔用的資源,支援以下各種型別的限制:

    所建立的核心檔案的大小、

    程序資料塊的大小、

    Shell 程序建立檔案的大小、

    記憶體鎖住的大小、

    常駐記憶體集的大小、

    開啟檔案描述符的數量、

    分配堆疊的最大大小、

    CPU 時間、

    單個使用者的最大執行緒數、

   Shell 程序所能使用的最大虛擬記憶體。同時,它支援硬資源和軟資源的限制。

作為臨時限制,ulimit 可以作用於通過使用其命令登入的 shell 會話,在會話終止時便結束限制,並不影響於其他 shell 會話。而對於長期的固定限制,ulimit 命令語句又可以被新增到由登入 shell 讀取的檔案中,作用於特定的 shell 使用者。

2、使用ulimit

ulimit 通過一些引數選項來管理不同種類的系統資源。

ulimit 命令的格式為:ulimit [options] [limit]

主要關注兩個:

1)open files:– 使用者可以開啟檔案的最大數目

對應ulimit 的命令ulimit -n,可以使用ulimit -n 臨時設定。

對應/etc/security/limits.conf的資源限制類型是:nofile

* soft nofile 4096    

 * hard nofile 4096

2)max user processes  – 使用者可以開啟程序/執行緒的最大數目

對應ulimit 的命令ulimit  -u  臨時修改max user processes的值:ulimit  -u   8192。

對應/etc/security/limits.conf的資源限制類型是:  noproc

*          soft    nproc     8192

具體的 options 含義以及簡單示例可以參考以下表格。
ulimit 引數說明

選項 含義

-a 顯示當前系統所有的limit資源資訊。 

-H 設定硬資源限制,一旦設定不能增加。例如:ulimit – Hs 64;限制硬資源,執行緒棧大小為 64K。

-S 設定軟資源限制,設定後可以增加,但是不能超過硬資源設定。例如:ulimit – Sn 32;限制軟資源,32 個檔案描述符。

-c 最大的core檔案的大小,以 blocks 為單位。例如:ulimit – c unlimited; 對生成的 core 檔案的大小不進行限制。

-f 程序可以建立檔案的最大值,以blocks 為單位.例如:ulimit – f 2048;限制程序可以建立的最大檔案大小為 2048 blocks。

-d 程序最大的資料段的大小,以Kbytes 為單位。例如:ulimit -d unlimited;對程序的資料段大小不進行限制。

-m 最大記憶體大小,以Kbytes為單位。例如:ulimit – m unlimited;對最大記憶體不進行限制。

-n 可以開啟的最大檔案描述符的數量。例如:ulimit – n 128;限制最大可以使用 128 個檔案描述符

-s 執行緒棧大小,以Kbytes為單位。例如:ulimit – s 512;限制執行緒棧的大小為 512 Kbytes。

-p 管道緩衝區的大小,以Kbytes 為單位。例如ulimit – p 512;限制管道緩衝區的大小為 512 Kbytes。

-u 使用者最大可用的程序數。例如 limit – u 65536;限制使用者最多可以使用 65536個程序。

-v 程序最大可用的虛擬記憶體,以Kbytes 為單位。ulimit – v 200000;限制最大可用的虛擬記憶體為 200000 Kbytes。

-t 最大CPU佔用時間,以秒為單位。ulimit – t unlimited;對最大的 CPU 佔用時間不進行限制。

-l 最大可加鎖記憶體大小,以Kbytes 為單位。

我們可以通過以下幾種方式來使用 ulimit:

一、在使用者的啟動指令碼中

        如果使用者使用的是 bash,就可以在使用者的目錄下的 .bashrc 檔案中,加入 ulimit – u 64,來限制使用者最多可以使用 64 個程序。此外,可以在與 .bashrc 功能相當的啟動指令碼中加入 ulimt。

二、在應用程式的啟動指令碼中

如果使用者要對某個應用程式 myapp 進行限制,可以寫一個簡單的指令碼 startmyapp。

ulimit – s 512
myapp

以後只要通過指令碼 startmyapp 來啟動應用程式,就可以限制應用程式 myapp 的執行緒棧大小為 512K。

三、直接在控制檯輸入 

 ulimit – p 256 

限制管道的緩衝區為 256K。

四、修改所有 linux 使用者的環境變數檔案:

    vi /etc/profile

    ulimit -u 10000

    ulimit -n 4096

    ulimit -d unlimited

    ulimit -m unlimited

    ulimit -s unlimited

    ulimit -t unlimited

    ulimit -v unlimited

 儲存後執行#source /etc/profile 使其生效

四、也可以針對單個使用者的.bash_profile設定:

vi ~./.bash_profile

#ulimit -n 1024
重新登陸ok

3、使用者程序的有效範圍

ulimit 作為對資源使用限制的一種工作,是有其作用範圍的。那麼,它限制的物件是單個使用者,單個程序,還是整個系統呢?事實上,ulimit 限制的是當前 shell 程序以及其派生的子程序。舉例來說,如果使用者同時運行了兩個 shell 終端程序,只在其中一個環境中執行了 ulimit – s 100,則該 shell 程序裡建立檔案的大小收到相應的限制,而同時另一個 shell終端包括其上執行的子程式都不會受其影響:

Shell 程序 1

ulimit –s 100
cat testFile > newFile
File size limit exceeded

Shell 程序 2

cat testFile > newFile
ls –s newFile
323669 newFile

針對使用者永久生效:

那麼,是否有針對某個具體使用者的資源加以限制的方法呢?答案是有的,方法是通過修改系統的 /etc/security/limits.conf配置檔案。該檔案不僅能限制指定使用者的資源使用,還能限制指定組的資源使用。該檔案的每一行都是對限定的一個描述。

limits.conf的格式如下:

<domain>                  <type>      <item>     <value> 

username|@groupname       type        resource          limit

domain:username|@groupname:設定需要被限制的使用者名稱,組名前面加@和使用者名稱區別。也可以用萬用字元*來做所有使用者的限制。

type:有 soft,hard 和 -,soft 指的是當前系統生效的設定值。hard 表明系統中所能設定的最大值。soft 的最大值不能超過hard的值。用 – 就表明同時設定了 soft 和 hard 的值。

resource:
    core – 限制核心檔案的大小
    date – 最大資料大小
    fsize – 最大檔案大小
    memlock – 最大鎖定記憶體地址空間
    nofile – 開啟檔案的最大數目
    rss – 最大持久設定大小
    stack – 最大棧大小
    cpu – 以分鐘為單位的最多 CPU 時間
    noproc – 程序的最大數目(系統的最大程序數)
    as – 地址空間限制
   maxlogins – 此使用者允許登入的最大數目

   要使 limits.conf 檔案配置生效,必須要確保 pam_limits.so 檔案被加入到啟動檔案中。

   檢視 /etc/pam.d/login 檔案中有:
   session required /lib/security/pam_limits.so

例如:解除 Linux 系統的最大程序數和最大檔案開啟數限制:  

        vi /etc/security/limits.conf  

        # 新增如下的行  

        * soft noproc 20000  #軟連線   

        * hard noproc 20000  #硬連線  

        * soft nofile 4096    

        * hard nofile 4096  

       說明:* 代表針對所有使用者,noproc 是代表最大程序數,nofile 是代表最大檔案開啟數

需要注意一點:/etc/security/limits.d下也有noproc最大進引數的限制:

即 /etc/security/limits.d/下的檔案覆蓋了/etc/security/limits.conf設定的值 

這個是官網答疑:https://access.redhat.com/solutions/406663

# /etc/security/limits.conf
#This file sets the resource limits for the users logged in via PAM.
#It does not affect resource limits of the system services.
#Also note that configuration files in /etc/security/limits.d directory,
#That means for example that setting a limit for wildcard domain here

[[email protected] ~]# cat /etc/security/limits.d/20-nproc.conf 
# Default limit for number of user's processes to prevent
# accidental fork bombs.
# See rhbz #432903 for reasoning.

*          soft    nproc     8192
root       soft    nproc     unlimited

現在已經可以對程序和使用者分別做資源限制了,看似已經足夠了,其實不然。很多應用需要對整個系統的資源使用做一個總的限制,這時候我們需要修改 /proc 下的配置檔案。/proc 目錄下包含了很多系統當前狀態的引數,例如 /proc/sys/kernel/pid_max,/proc/sys/net/ipv4/ip_local_port_range 等等,從檔案的名字大致可以猜出所限制的資源種類。

注意:

通過讀取/proc/sys/fs/file-nr可以看到當前使用的檔案描述符總數。另外,對於檔案描述符的配置,需要注意以下幾點:

  • 所有程序開啟的檔案描述符數不能超過/proc/sys/fs/file-max

  • 單個程序開啟的檔案描述符數不能超過user limit中nofile的soft limit

  • nofile的soft limit不能超過其hard limit

  • nofile的hard limit不能超過/proc/sys/fs/nr_open

4、使用者程序的有效範圍

 問題1:su切換使用者時提示:Resource temporarily unavailable

或者通過程序跟蹤 strace -p pid 看到:Resource temporarily unavailab

通過ulimit -a,得到結果:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 63463
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 4096
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

在上面這些引數中,通常我們關注得比較多:

open files: 一個程序可開啟的最大檔案數.

max user processes: 系統允許建立的最大程序數量.

通過 ps -efL|grep java |wc -l

#24001

這個得到的執行緒數竟然是2萬多,遠遠超過4096

我們可以使用 ulimit -u 20000 修改max user processes的值,但是隻能在當前終端的這個session裡面生效,重新登入後仍然是使用系統預設值。

正確的修改方式是修改/etc/security/limits.d/20-nproc.conf檔案中的值。先看一下這個檔案包含什麼:

$ cat /etc/security/limits.d/90-nproc.conf 
# Default limit for number of user's processes to prevent
# accidental fork bombs.
# See rhbz #432903 for reasoning.

*          soft    nproc    8192

我們只要修改上面檔案中的8192這個值,即可。

問題2:linux 開啟檔案數 too many open files 解決方法

在執行某些命令或者 tomcat等伺服器持續執行 一段時間後可能遇到   too many open files。

出現這句提示的原因是程式開啟的檔案/socket連線數量超過系統設定值。

java程序如果遇到java.net.SocketException: Too many open files,接著可能導致域名解析ava.net.UnknownHostException:

原因是使用者程序無法開啟系統檔案了。

檢視每個使用者最大允許開啟檔案數量

ulimit -a

其中 open files (-n) 65535 表示每個使用者最大允許開啟的檔案數量是65535 。 預設是1024。1024很容易不夠用。

永久修改open files 方法

vim /etc/security/limits.conf  
在最後加入  
* soft nofile 65535 
* hard nofile 65535  

或者只加入

 * - nofile 65535

最前的 * 表示所有使用者,可根據需要設定某一使用者,例如
fdipzone soft nofile 8192  
fdipzone hard nofile 8192  

注意"nofile"項有兩個可能的限制措施。就是項下的hard和soft。 要使修改過得最大開啟檔案數生效,必須對這兩種限制進行設定。 如果使用"-"字元設定, 則hard和soft設定會同時被設定。 
改完後登出一下就能生效。

通過 ulimit -n或者ulimit -a 檢視系統的最大檔案開啟數已經生效了。但此時檢視程序的最大檔案開啟數沒有變,原因是這個值是在程序啟動的時候設定的,要生效必須重啟!

ok,那就重啟吧,重啟完畢,結果發現依然沒變!這奇了怪了,後來經過好久的排查,最終確認問題是,該程式是通過 supervisord來管理的,也就是這程序都是 supervisord 的子程序,而 supervisord 的最大檔案開啟數還是老的配置,此時必須重啟 supervisord 才可以。

當大家遇到limits修改不生效的時候,請查一下程序是否只是子程序,如果是,那就要把父程序也一併重啟才可以。