linux/unix ulimit命令詳解

xiexingzhi發表於2012-09-05
Linux對於每個使用者,系統限制其最大程式數。為提高效能,可以根據裝置資源情況,設定各linux 使用者的最大程式數
可以用ulimit -a 來顯示當前的各種使用者程式限制。
下面我把某linux使用者的最大程式數設為10000個:
     ulimit -u 10240
     對於需要做許多 socket 連線並使它們處於開啟狀態的 Java 應用程式而言,
     最好通過使用 ulimit -n xx 修改每個程式可開啟的檔案數,預設值是 1024。
     ulimit -n 4096 將每個程式可以開啟的檔案數目加大到4096,預設為1024
     其他建議設定成無限制(unlimited)的一些重要設定是:
     資料段長度:ulimit -d unlimited
     最大記憶體大小:ulimit -m unlimited
     堆疊大小:ulimit -s unlimited
     CPU 時間:ulimit -t unlimited
     虛擬記憶體:ulimit -v unlimited
  
     暫時地,適用於通過 ulimit 命令登入 shell 會話期間。
     永久地,通過將一個相應的 ulimit 語句新增到由登入 shell 讀取的檔案中, 即特定於 shell 的使用者資原始檔,如:
1)、解除 Linux 系統的最大程式數和最大檔案開啟數限制:
        vi /etc/security/limits.conf
        # 新增如下的行
        * soft noproc 11000
        * hard noproc 11000
        * soft nofile 4100
        * hard nofile 4100
       說明:* 代表針對所有使用者,noproc 是代表最大程式數,nofile 是代表最大檔案開啟數
2)、讓 SSH 接受 Login 程式的登入,方便在 ssh 客戶端檢視 ulimit -a 資源限制:
        a、vi /etc/ssh/sshd_config
             把 UserLogin 的值改為 yes,並把 # 註釋去掉
        b、重啟 sshd 服務:
              /etc/init.d/sshd restart
3)、修改所有 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 使其生效
/**************************************
有時候在程式裡面需要開啟多個檔案,進行分析,系統一般預設數量是1024,(用ulimit -a可以看到)對於正常使用是夠了,但是對於程式來講,就太少了。
修改2個檔案。

1./etc/security/limits.conf
vi /etc/security/limits.conf
加上:
* soft nofile 8192
* hard nofile 20480

2./etc/pam.d/login
session required /lib/security/pam_limits.so
/**********
另外確保/etc/pam.d/system-auth檔案有下面內容
session required /lib/security/$ISA/pam_limits.so
這一行確保系統會執行這個限制。

/***********
3.一般使用者的.bash_profile
#ulimit -n 1024
重新登陸ok
 
ulimit 的作用
  =======================
 
ulimit:顯示(或設定)使用者可以使用的資源的限制(limit),這限制分為軟限制(當前限制)和硬限制(上限),其中硬限制是軟限制的上限值,應用程式在執行過程中使用的系統資源不超過相應的軟限制,任何的超越都導致程式的終止。

引數 描述
ulimited 不限制使用者可以使用的資源,但本設定對可開啟的最大檔案數(max open files)
和可同時執行的最大程式數(max user processes)無效
-a 列出所有當前資源極限
-c 設定core檔案的最大值.單位:blocks
-d 設定一個程式的資料段的最大值.單位:kbytes
-f Shell 建立檔案的檔案大小的最大值,單位:blocks
-h 指定設定某個給定資源的硬極限。如果使用者擁有 root 使用者許可權,可以增大硬極限。任何使用者均可減少硬極限
-l 可以鎖住的實體記憶體的最大值
-m 可以使用的常駐記憶體的最大值,單位:kbytes
-n 每個程式可以同時開啟的最大檔案數
-p 設定管道的最大值,單位為block,1block=512bytes
-s 指定堆疊的最大值:單位:kbytes
-S 指定為給定的資源設定軟極限。軟極限可增大到硬極限的值。如果 -H 和 -S 標誌均未指定,極限適用於以上二者
-t 指定每個程式所使用的秒數,單位:seconds
-u 可以執行的最大併發程式數
-v Shell可使用的最大的虛擬記憶體,單位:kbytes
-x
範例1:
[root@localhost proc]# ulimit -a
core file size (blocks, -c) 100
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
pending signals (-i) 2047
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 2047
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
[root@localhost proc]#
輸出的每一行由資源名字、(單位,ulimit命令的引數)、軟限制組成。詳細解釋:
引數 描述
core file size core檔案的最大值為100 blocks,
data seg size 程式的資料段可以任意大
file size 檔案可以任意大
pending signals 最多有2047個待處理的訊號
max locked memory 一個任務鎖住的實體記憶體的最大值為32kB
max memory size 一個任務的常駐實體記憶體的最大值
open files 一個任務最多可以同時開啟1024的檔案
pipe size 管道的最大空間為4096位元組
POSIX message queues POSIX的訊息佇列的最大值為819200位元組
stack size 程式的棧的最大值為8192位元組
cpu time 程式使用的CPU時間
max user processes 當前使用者同時開啟的程式(包括執行緒)的最大個數為2047
virtual memory 沒有限制程式的最大地址空間
file locks 所能鎖住的檔案的最大個數沒有限制
範例2:通過ulimit命令來限制檔案的大小,從而導致拷貝命令的失敗
[root@localhost]ls temp.txt
ls: temp.txt: 沒有那個檔案或目錄
[root@localhost]ulimit -f 1 #設定建立檔案的最大塊(一塊=512位元組)
[root@localhost]cat a.c > temp.txt
檔案大小超出限制
檔案a.c的大小是5002位元組,而我們設定的建立檔案的大小是512位元組x1塊=512位元組 


1、修改使用者程式可開啟檔案數限制

在Linux平臺上,無論編寫客戶端程式還是服務端程式,在進行高並發TCP連線處理時,最高的並發數量都要受到系統對使用者單一程式同時可開啟檔案數量的限制(這是因為系統為每個TCP連線都要建立一個socket控制程式碼,每個socket控制程式碼同時也是一個檔案控制程式碼)。可使用ulimit命令檢視系統允許當前使用者程式開啟的檔案數限制:

[speng@as4 ~]$ ulimit -n

1024

這表示當前使用者的每個程式最多允許同時開啟1024個檔案,這1024個檔案中還得除去每個程式必然開啟的標準輸入,標準輸出,標準錯誤,伺服器監聽socket,程式間通訊的unix域socket等檔案,那麼剩下的可用於客戶端socket連線的檔案數就只有大概1024-10=1014個左右。也就是說預設情況下,基於Linux的通訊程式最多允許同時1014個TCP並發連線。

對於想支援更高數量的TCP並發連線的通訊處理程式,就必須修改Linux對當前使用者的程式同時開啟的檔案數量的軟限制(soft limit)和硬限制(hardlimit)。其中軟限制是指Linux在當前系統能夠承受的範圍內進一步限制使用者同時開啟的檔案數;硬限制則是根據系統硬體資源狀況(主要是系統記憶體)計算出來的系統最多可同時開啟的檔案數量。通常軟限制小於或等於硬限制。

修改上述限制的最簡單的辦法就是使用ulimit命令:

[speng@as4 ~]$ ulimit -n

上述命令中,在中指定要設定的單一程式允許開啟的最大檔案數。如果系統回顯類似於"Operation notpermitted"之類的話,說明上述限制修改失敗,實際上是因為在中指定的數值超過了Linux系統對該使用者開啟檔案數的軟限製或硬限制。因此,就需要修改Linux系統對使用者的關於開啟檔案數的軟限制和硬限制。

第一步,修改/etc/security/limits.conf檔案,在檔案中新增如下行:

speng soft nofile 10240

speng hard nofile 10240

其中speng指定了要修改哪個使用者的開啟檔案數限制,可用'*'號表示修改所有使用者的限制;soft或hard指定要修改軟限制還是硬限制;10240則指定了想要修改的新的限制值,即最大開啟檔案數(請注意軟限制值要小於或等於硬限制)。修改完後儲存檔案。

第二步,修改/etc/pam.d/login檔案,在檔案中新增如下行:

session required /lib/security/pam_limits.so

這是告訴Linux在使用者完成系統登入後,應該呼叫pam_limits.so模組來設定系統對該使用者可使用的各種資源數量的最大限制(包括使用者可開啟的最大檔案數限制),而pam_limits.so模組就會從/etc/security/limits.conf檔案中讀取配置來設定這些限制值。修改完後儲存此檔案。

第三步,檢視Linux系統級的最大開啟檔案數限制,使用如下命令:

[speng@as4 ~]$ cat /proc/sys/fs/file-max

12158

這表明這臺Linux系統最多允許同時開啟(即包含所有使用者開啟檔案數總和)12158個檔案,是Linux系統級硬限制,所有使用者級的開啟檔案數限制都不應超過這個數值。通常這個系統級硬限制是Linux系統在啟動時根據系統硬體資源狀況計算出來的最佳的最大同時開啟檔案數限制,如果沒有特殊需要,不應該修改此限制,除非想為使用者級開啟檔案數限制設定超過此限制的值。修改此硬限制的方法是修改/etc/rc.local指令碼,在指令碼中新增如下行:

echo 22158 > /proc/sys/fs/file-max

這是讓Linux在啟動完成後強行將系統級開啟檔案數硬限制設定為22158。修改完後儲存此檔案。

完成上述步驟後重啟系統,一般情況下就可以將Linux系統對指定使用者的單一程式允許同時開啟的最大檔案數限制設為指定的數值。如果重啟後用ulimit-n命令檢視使用者可開啟檔案數限制仍然低於上述步驟中設定的最大值,這可能是因為在使用者登入指令碼/etc/profile中使用ulimit -n命令已經將使用者可同時開啟的檔案數做了限制。由於通過ulimit-n修改系統對使用者可同時開啟檔案的最大數限制時,新修改的值只能小於或等於上次ulimit-n設定的值,因此想用此命令增大這個限制值是不可能的。所以,如果有上述問題存在,就只能去開啟/etc/profile指令碼檔案,在檔案中查詢是否使用了ulimit-n限制了使用者可同時開啟的最大檔案數量,如果找到,則刪除這行命令,或者將其設定的值改為合適的值,然後儲存檔案,使用者退出並重新登入系統即可。

通過上述步驟,就為支援高並發TCP連線處理的通訊處理程式解除關於開啟檔案數量方面的系統限制。

2、修改網路核心對TCP連線的有關限制

在Linux上編寫支援高並發TCP連線的客戶端通訊處理程式時,有時會發現儘管已經解除了系統對使用者同時開啟檔案數的限制,但仍會出現並發TCP連線數增加到一定數量時,再也無法成功建立新的TCP連線的現象。出現這種現在的原因有多種。

第一種原因可能是因為Linux網路核心對本地埠號範圍有限制。此時,進一步分析為什麼無法建立TCP連線,會發現問題出在connect()呼叫返回失敗,檢視系統錯誤提示訊息是"Can't assign requestedaddress"。同時,如果在此時用tcpdump工具監視網路,會發現根本沒有TCP連線時客戶端發SYN包的網路流量。這些情況說明問題在於本地Linux系統核心中有限制。其實,問題的根本原因在於Linux核心的TCP/IP協議實現模組對系統中所有的客戶端TCP連線對應的本地埠號的範圍進行了限制(例如,核心限製本地埠號的範圍為1024~32768之間)。當系統中某一時刻同時存在太多的TCP客戶端連線時,由於每個TCP客戶端連線都要佔用一個唯一的本地埠號(此埠號在系統的本地埠號範圍限制中),如果現有的TCP客戶端連線已將所有的本地埠號佔滿,則此時就無法為新的TCP客戶端連線分配一個本地埠號了,因此係統會在這種情況下在connect()呼叫中返回失敗,並將錯誤提示訊息設為"Can't assignrequested address"。有關這些控制邏輯可以檢視Linux核心原始碼,以linux2.6核心為例,可以檢視tcp_ipv4.c檔案中如下函式:

static int tcp_v4_hash_connect(struct sock *sk)

請注意上述函式中對變數sysctl_local_port_range的訪問控制。變數sysctl_local_port_range的初始化則是在tcp.c檔案中的如下函式中設定:

void __init tcp_init(void)

核心編譯時預設設定的本地埠號範圍可能太小,因此需要修改此本地埠範圍限制。

第一步,修改/etc/sysctl.conf檔案,在檔案中新增如下行:

net.ipv4.ip_local_port_range = 1024 65000

這表明將系統對本地埠範圍限制設定為1024~65000之間。請注意,本地埠範圍的最小值必須大於或等於1024;而埠範圍的最大值則應小於或等於65535。修改完後儲存此檔案。

第二步,執行sysctl命令:

[speng@as4 ~]$ sysctl -p

如果系統沒有錯誤提示,就表明新的本地埠範圍設定成功。如果按上述埠範圍進行設定,則理論上單獨一個程式最多可以同時建立60000多個TCP客戶端連線。

第二種無法建立TCP連線的原因可能是因為Linux網路核心的IP_TABLE防火牆對最大跟蹤的TCP連線數有限制。此時程式會表現為在connect()呼叫中阻塞,如同當機,如果用tcpdump工具監視網路,也會發現根本沒有TCP連線時客戶端發SYN包的網路流量。由於IP_TABLE防火牆在核心中會對每個TCP連線的狀態進行跟蹤,跟蹤資訊將會放在位於核心記憶體中的conntrackdatabase中,這個資料庫的大小有限,當系統中存在過多的TCP連線時,資料庫容量不足,IP_TABLE無法為新的TCP連線建立跟蹤資訊,於是表現為在connect()呼叫中阻塞。此時就必須修改核心對最大跟蹤的TCP連線數的限制,方法同修改核心對本地埠號範圍的限制是類似的:

第一步,修改/etc/sysctl.conf檔案,在檔案中新增如下行:

net.ipv4.ip_conntrack_max = 10240

這表明將系統對最大跟蹤的TCP連線數限制設定為10240。請注意,此限制值要盡量小,以節省對核心記憶體的佔用。

第二步,執行sysctl命令:

[speng@as4 ~]$ sysctl -p

如果系統沒有錯誤提示,就表明系統對新的最大跟蹤的TCP連線數限制修改成功。如果按上述引數進行設定,則理論上單獨一個程式最多可以同時建立10000多個TCP客戶端連線。

*******注意*******

sysctl -p 報錯net.ipv4.ip_conntrack_max" is an unknown key 則:modprobe ip_conntrack

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22531473/viewspace-742736/,如需轉載,請註明出處,否則將追究法律責任。

相關文章