“Too many open files”是一個比較常見的錯誤,不僅僅是在 MySQL 中。只要是在 Linux 中啟動的程式,都有可能遇到這個錯誤。
究其原因,是程式開啟的檔案描述符數超過了自身的限制。
這個限制,是程式級別的,在 MySQL 中,與 open_files_limit 的設定有關。
但是 open_files_limit 並不是所設即所得,配置的和實際生效的並不完全一樣。
一、測試Demo
配置檔案中的配置。
open_files_limit = 65536 table_open_cache = 1000 max_connections = 2000
切換到 mysql 使用者下,啟動例項,看看這三個引數,外加 table_definition_cache 的實際有效值。
[root@node1 ~]# su - mysql [mysql@node1 ~]$ /usr/local/mysql5.7.34/bin/mysqld --defaults-file=/etc/my.cnf & mysql> select @@open_files_limit,@@table_open_cache,@@max_connections,@@table_definition_cache; +--------------------+--------------------+-------------------+--------------------------+ | @@open_files_limit | @@table_open_cache | @@max_connections | @@table_definition_cache | +--------------------+--------------------+-------------------+--------------------------+ | 2048 | 400 | 1238 | 600 | +--------------------+--------------------+-------------------+--------------------------+ 1 row in set (0.01 sec)
實際值和配置值,竟然沒有一個相同,是不是很意外?
二、原始碼分析
下面,結合原始碼看看這三個引數的生成邏輯。
# vim mysql-5.7.34/sql/mysqld.cc
#ifdef _WIN32 int win_main(int argc, char **argv) #else int mysqld_main(int argc, char **argv) #endif { ... sys_var_init(); ulong requested_open_files; adjust_related_options(&requested_open_files); ... }
其中:
-
sys_var_init():初始化系統引數(System Variables)。
-
adjust_related_options():在初始化的基礎上,調整相關引數的配置。
下面看看 adjust_related_options 的處理邏輯
void adjust_related_options(ulong *requested_open_files) { /* In bootstrap, disable grant tables (we are about to create them) */ if (opt_bootstrap) opt_noacl= 1; /* The order is critical here, because of dependencies. */ adjust_open_files_limit(requested_open_files); adjust_max_connections(*requested_open_files); adjust_table_cache_size(*requested_open_files); adjust_table_def_size(); }
其中,
-
adjust_open_files_limit:調整 open_files_limit,調整後的值會賦值給 requested_open_files。
-
adjust_max_connections:調整 max_connections,依賴於 requested_open_files,即調整後的 open_files_limit。
-
adjust_table_cache_size:調整 table_cache_size,依賴於調整後的 open_files_limit 和 max_connections。
-
adjust_table_def_size:調整 table_definition_cache,依賴於調整後的 table_cache_size。
這四個引數中,最為複雜的是 open_files_limit 的調整,它涉及到系統對程式能開啟的最大檔案描述符的限制。
不妨,先基於調整後的 open_files_limit,看看後面三個引數的調整邏輯。
2.1 max_connections
首先,看看 max_connections 的取值邏輯
void adjust_max_connections(ulong requested_open_files) { ulong limit; limit= requested_open_files - 10 - TABLE_OPEN_CACHE_MIN * 2; if (limit < max_connections) { sql_print_warning("Changed limits: max_connections: %lu (requested %lu)", limit, max_connections); // This can be done unprotected since it is only called on startup. max_connections= limit; } }
其中,
-
requested_open_files:調整後的 open_files_limit。具體在本 Demo,是 2048。
-
TABLE_OPEN_CACHE_MIN:常量,代表 table_cache_size 可允許的最小值。
#define TABLE_OPEN_CACHE_MIN 400
-
max_connections:max_connections 的初始值。取配置檔案中的配置,2000。如果配置檔案中沒有設定,則預設為 151。
基於程式碼中的計算邏輯,limit = 2048 - 10 - 400 * 2 = 1238。
1238 小於 2000,所以 max_connections 最後取值為 1238,與 Demo 開頭的查詢結果一致。
2.2 table_cache_size
接下來,看看 table_cache_size 的取值邏輯
void adjust_table_cache_size(ulong requested_open_files) { ulong limit; limit= max<ulong>((requested_open_files - 10 - max_connections) / 2, TABLE_OPEN_CACHE_MIN); if (limit < table_cache_size) { sql_print_warning("Changed limits: table_open_cache: %lu (requested %lu)", limit, table_cache_size); table_cache_size= limit; } table_cache_size_per_instance= table_cache_size / table_cache_instances; }
其中,
-
max_connections:max_connections 調整後的的值,即 1238。
-
table_cache_instances:table_open_cache_instances。
-
table_cache_size:table_cache_size 的初始值。在這個 Demo 中,是 1000。
基於程式碼中的計算邏輯,limit = max( ( 2048 - 10 - 1238 ) / 2,400 ) = 400。
400 小於 1000,所以,table_cache_size 最後取值為 400。
2.3 table_definition_cache
接下來,看看 table_definition_cache 的取值邏輯
void adjust_table_def_size() { ulong default_value; sys_var *var; default_value= min<ulong> (400 + table_cache_size / 2, 2000); var= intern_find_sys_var(STRING_WITH_LEN("table_definition_cache")); assert(var != NULL); var->update_default(default_value); if (! table_definition_cache_specified) table_def_size= default_value; }
同樣,table_cache_size 也是調整後的值,即 400。
default_value = min( 400 + 400 / 2,2000) = 600。
顧名思義,default_value 是預設值。如果沒有顯式設定 table_definition_cache,則取預設值。
2.4 open_files_limit
最後看看 open_files_limit 的取值邏輯
void adjust_open_files_limit(ulong *requested_open_files) { ulong limit_1; ulong limit_2; ulong limit_3; ulong request_open_files; ulong effective_open_files; /* MyISAM requires two file handles per table. */ limit_1= 10 + max_connections + table_cache_size * 2; /* We are trying to allocate no less than max_connections*5 file handles (i.e. we are trying to set the limit so that they will be available). */ limit_2= max_connections * 5; /* Try to allocate no less than 5000 by default. */ limit_3= open_files_limit ? open_files_limit : 5000; request_open_files= max<ulong>(max<ulong>(limit_1, limit_2), limit_3); /* Notice: my_set_max_open_files() may return more than requested. */ effective_open_files= my_set_max_open_files(request_open_files); if (effective_open_files < request_open_files) { if (open_files_limit == 0) { sql_print_warning("Changed limits: max_open_files: %lu (requested %lu)", effective_open_files, request_open_files); } else { sql_print_warning("Could not increase number of max_open_files to " "more than %lu (request: %lu)", effective_open_files, request_open_files); } } open_files_limit= effective_open_files; if (requested_open_files) *requested_open_files= min<ulong>(effective_open_files, request_open_files); }
因為是最先調整的引數,所以,這裡的 max_connections,table_cache_size,open_files_limit 都是初始值。
基於程式碼中的計算邏輯,
-
limit_1 = 10 + max_connections + table_cache_size _ 2 = 10 + 2000 + 1000 _ 2 = 4100
-
limit_2 = max_connections _ 5 = 2000 _ 5 = 10000
-
limit_3 = open_files_limit ? open_files_limit : 5000 = 65536
request_open_files = max(max(limit_1, limit_2), limit_3) = 65536,可理解為需要開啟的檔案數。
接下來,呼叫 my_set_max_open_files 函式獲取 effective_open_files,後者是實際能開啟的最大檔案數。
看看 my_set_max_open_files 的處理邏輯。
uint my_set_max_open_files(uint files) { struct st_my_file_info *tmp; DBUG_ENTER("my_set_max_open_files"); DBUG_PRINT("enter",("files: %u my_file_limit: %u", files, my_file_limit)); files+= MY_FILE_MIN; files= set_max_open_files(MY_MIN(files, OS_FILE_LIMIT)); if (files <= MY_NFILE) DBUG_RETURN(files); if (!(tmp= (struct st_my_file_info*) my_malloc(key_memory_my_file_info, sizeof(*tmp) * files, MYF(MY_WME)))) DBUG_RETURN(MY_NFILE); /* Copy any initialized files */ memcpy((char*) tmp, (char*) my_file_info, sizeof(*tmp) * MY_MIN(my_file_limit, files)); memset((tmp + my_file_limit), 0, MY_MAX((int) (files - my_file_limit), 0) * sizeof(*tmp)); my_free_open_file_info(); /* Free if already allocated */ my_file_info= tmp; my_file_limit= files; DBUG_PRINT("exit",("files: %u", files)); DBUG_RETURN(files); }
相關的常量定義如下:
#ifdef _WIN32 #define MY_FILE_MIN 2048 #else #define MY_FILE_MIN 0 #endif #ifdef _WIN32 #define MY_NFILE (16384 + MY_FILE_MIN) #else #define MY_NFILE 64 #endif #define MY_MIN(a, b) ((a) < (b) ? (a) : (b)) #define OS_FILE_LIMIT UINT_MAX
可見,在 Linux 系統中,MY_MIN(files, OS_FILE_LIMIT)還是等於 files,即 request_open_files。
這段程式碼裡,重點還是呼叫 set_max_open_files 函式。
下面看看 set_max_open_files 的處理邏輯。
static uint set_max_open_files(uint max_file_limit) { struct rlimit rlimit; uint old_cur; DBUG_ENTER("set_max_open_files"); DBUG_PRINT("enter",("files: %u", max_file_limit)); if (!getrlimit(RLIMIT_NOFILE,&rlimit)) { old_cur= (uint) rlimit.rlim_cur; DBUG_PRINT("info", ("rlim_cur: %u rlim_max: %u", (uint) rlimit.rlim_cur, (uint) rlimit.rlim_max)); if (rlimit.rlim_cur == (rlim_t) RLIM_INFINITY) rlimit.rlim_cur = max_file_limit; if (rlimit.rlim_cur >= max_file_limit) DBUG_RETURN(rlimit.rlim_cur); /* purecov: inspected */ rlimit.rlim_cur= rlimit.rlim_max= max_file_limit; if (setrlimit(RLIMIT_NOFILE, &rlimit)) max_file_limit= old_cur; /* Use original value */ else { rlimit.rlim_cur= 0; /* Safety if next call fails */ (void) getrlimit(RLIMIT_NOFILE,&rlimit); DBUG_PRINT("info", ("rlim_cur: %u", (uint) rlimit.rlim_cur)); if (rlimit.rlim_cur) /* If call didn't fail */ max_file_limit= (uint) rlimit.rlim_cur; } } DBUG_PRINT("exit",("max_file_limit: %u", max_file_limit)); DBUG_RETURN(max_file_limit); }
這裡,使用了兩個系統函式:getrlimit(),setrlimit(),分別用來獲取和設定系統的資源限制(resource limit)。
#include <sys/resource.h> int getrlimit(int resource, struct rlimit *rlim); int setrlimit(int resource, const struct rlimit *rlim);
其中,
-
resource:資源型別。
可設定的資源型別有:RLIMIT_AS,RLIMIT_CORE,RLIMIT_CPU,RLIMIT_DATA,RLIMIT_FSIZE,RLIMIT_LOCKS,RLIMIT_MEMLOCK,RLIMIT_MSGQUEUE,RLIMIT_NICE,RLIMIT_NOFILE,RLIMIT_NPROC,RLIMIT_RSS,RLIMIT_RTPRIO,RLIMIT_RTTIME,RLIMIT_SIGPENDING,RLIMIT_STACK。
其中,RLIMIT_NOFILE 代表程式能開啟的最大檔案描述符數。
-
rlimit:結構體,定義了兩個變數。
struct rlimit { rlim_t rlim_cur; /* Soft limit */ rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */ };
其中,rlim_cur 代表軟限制,rlim_max 代表硬限制。
注意:資源限制,真正起限制作用的是軟限制,硬限制只是限制了軟限制可設定的上限。
這兩個函式,如果呼叫成功,則返回 0,反之,則返回-1。
瞭解完背景知識,接下來看看set_max_open_files具體的處理邏輯。
首先,獲取程式的 RLIMIT_NOFILE。在此基礎上,
-
如果軟限制等於 RLIM_INFINITY(無限制),則將 max_file_limit 賦值給軟限制。
-
如果軟限制大於等於 max_file_limit,則返回軟限制,並退出函式。
這就意味著,在軟限制大於等於 max_file_limit 的情況下:
-
軟限制等於 RLIM_INFINITY(無限制),返回的是 max_file_limit。
-
軟限制不是 RLIM_INFINITY,且大於 max_file_limit,則返回軟限制。
接下來,就只有一種情況,即軟限制小於max_file_limit。此時,會將max_file_limit賦值給軟限制和硬限制,並嘗試修改程式的RLIMIT_NOFILE。
-
如果不能修改成功,則將程式的軟限制賦值給 max_file_limit。
-
如果能修改成功,則再次獲取程式的 RLIMIT_NOFILE,將其賦值給 max_file_limit。這樣做,可避免修改實際沒有生效的問題。
這就意味著,在軟限制小於 max_file_limit 的情況下:
-
如果不能修改程式的 RLIMIT_NOFILE,則返回的是軟限制。
-
如果能修改程式的 RLIMIT_NOFILE,則返回的是 max_file_limit。
什麼情況下,能修改成功呢?
-
mysqld 是在普通使用者下啟動的,修改後的軟限制(即 max_file_limit)小於硬限制。
-
mysqld 是在 root 使用者下啟動的或 mysqld 程式有 CAP_SYS_RESOURCE(忽略資源限制)許可權。
注意,這裡的啟動使用者指的是啟動 mysqld_safe 或 mysqld 的使用者,不是執行使用者(配置檔案中指定的 user)。
既然 max_file_limit 的設定與程式的 RLIMIT_NOFILE 的有關,接下來,我們看看該程式的 RLIMIT_NOFILE。
# cat /proc/26424/limits Limit Soft Limit Hard Limit Units ... Max open files 2048 4096 files ...
其中,26424 是程式的 PID。
2048 是軟限制,4096 是硬限制。
回到原始碼,啟動使用者是 mysql,2048 小於 65536,且 65536 大於 4096,所以不能修改程式的 RLIMIT_NOFILE。故而,最後,我們看到的 open_files_limit 是 2048。
三、程式RLIMIT_NOFILE的決定因素
同樣的設定,如果 mysqld 是在 root 使用者下啟動呢?
[root@node1 ~]# /usr/local/mysql5.7.34/bin/mysqld --defaults-file=/etc/my.cnf & mysql> select @@open_files_limit,@@table_open_cache,@@max_connections,@@table_definition_cache; +--------------------+--------------------+-------------------+--------------------------+ | @@open_files_limit | @@table_open_cache | @@max_connections | @@table_definition_cache | +--------------------+--------------------+-------------------+--------------------------+ | 100000 | 1000 | 2000 | 900 | +--------------------+--------------------+-------------------+--------------------------+ 1 row in set (0.00 sec)
竟然不是 65536,而是 100000。
3.1 啟動使用者
這個實際上與啟動使用者有關。使用者決定了通過它啟動的程式的資源上限,包括檔案描述符數。
這裡的上限,是在/etc/security/limits.conf 中定義的。如本 Demo 中的配置,
root soft nofile 100000 root hard nofile 100000 mysql soft nofile 2048 mysql hard nofile 4096
注意,這裡雖然配置的是使用者,但實際上限制的是通過使用者啟動的程式。
一般建議顯式設定,如果不設定的話,則預設是 1024。1024,對於大多數應用來說,還是太小了。
使用者可自由調整軟限制和硬限制的大小,但需遵循以下規則:
-
軟限制必須小於等於硬限制。
-
硬限制可以調小,但不能低於軟限制。
除此之外,
-
如果是普通使用者,對於硬限制的調整是不可逆的,即一旦調小,就不能再調大。
-
如果是 root 使用者,則沒有限制。但不能無限調大,最大值受到/proc/sys/fs/nr_open 的限制。後者決定了單個程式可開啟的最大檔案描述符數。
3.2 啟動指令碼
除了啟動使用者,啟動指令碼也能限制程式的資源使用。
看下面這個 Demo,同樣是在 root 使用者下,只不過這次是通過 mysqld_safe 啟動。
同樣是在 root 使用者下,如果是通過 mysqld_safe 啟動呢?
[root@node1 ~]# /usr/local/mysql5.7.34/bin/mysqld_safe --defaults-file=/etc/my.cnf & mysql> select @@open_files_limit,@@table_open_cache,@@max_connections,@@table_definition_cache; +--------------------+--------------------+-------------------+--------------------------+ | @@open_files_limit | @@table_open_cache | @@max_connections | @@table_definition_cache | +--------------------+--------------------+-------------------+--------------------------+ | 65536 | 1000 | 2000 | 900 | +--------------------+--------------------+-------------------+--------------------------+ 1 row in set (0.00 sec)
竟然是 65536。
這背後,其實是 mysqld_safe 在“搗鬼”。
USER_OPTION="" if test -w / -o "$USER" = "root" then if test "$user" != "root" -o $SET_USER = 1 then USER_OPTION="--user=$user" fi if test -n "$open_files" then ulimit -n $open_files fi fi parse_arguments() { ... --open-files-limit=*) open_files="$val" ;; --open_files_limit=*) open_files="$val" ;; ... }
具體來說,如果配置檔案或命令列中顯式設定了 open_files_limit,則 mysqld_safe 在啟動的過程中會通過“ulimit -n $open_files”調整程式的最大檔案描述符數。
除了啟動指令碼,在 CentOS 7 中,如果是通過 systemd 管理程式,還可通過 LimitNOFILE 在程式級別設定檔案描述符數的上限。
LimitNOFILE=102400
3.3 小結
程式能開啟的最大檔案描述符數由啟動使用者決定。除此之外,啟動指令碼(包括systemd),能在程式級別設定檔案描述符數的上限。
四、Too many open files
檔案描述符不夠,在 MySQL 中的影響主要有:
-
連線建立失敗。相關的報錯如下:
[ERROR] Error in accept: Too many open files in system
-
查詢失敗。相關的報錯如下:
[ERROR] /usr/local/mysql5.7.34/bin/mysqld: Can't open file: './sbtest/t4.frm' (errno: 24 - Too many open files)
4.1 常見原因
出現“Too many open files”,常見的原因有兩個:
-
系統可開啟的檔案描述符數達到了上限。這裡的上限,指的是系統核心的上限,由/proc/sys/fs/file-max 決定。
-
程式可開啟的檔案描述符數達到了上限。
之所以要區分這兩種場景,是因為兩者的解決方法不一樣。
如何判斷是哪個原因導致的呢?
-
檢視系統檔案描述符的使用情況。
cat /proc/sys/fs/file-nr 2752 0 65536
輸出有三列,如果第一列大於等於第三列,則意味著系統可開啟的檔案描述符數達到了上限。
- 第一列:已分配的檔案描述符數。
- 第二列:可用的檔案描述符數。
- 第三列:核心能分配的最大檔案描述符數,由/proc/sys/fs/file-max 決定。
/var/log/messages。
如果系統可開啟的檔案描述符數達到了上限,/var/log/messages 還會出現以下報錯。
kernel: [8314414.667267] VFS: file-max limit 65536 reached
4.2 解決方法
確定了原因,下面看看解決方法。
4.2.1 針對原因一,系統可使用的檔案描述符數達到了上限。
-
看看哪些程式開啟的檔案最多。
lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr
輸出有兩列,第一列是開啟的檔案的個數,第二列是程式號。
-
通過程式號定位具體的程式。
ps -ef | grep ${PID}
-
分析開啟檔案最多的程式,或 KILL,或重啟,或優化。
-
如果短期內不能優化解決的,可先臨時調大 file-max 的值。
echo 100000 > /proc/sys/fs/file-max
這裡修改的是記憶體值,機器重啟就會失效。如果要永久生效,還需修改/etc/sysctl.conf。
# vim /etc/sysctl.conf fs.file-max=100000 # sysctl -p
4.2.2 針對原因二,程式可使用的檔案描述符數達到了上限。
-
檢視程式的最大檔案描述符數。
cat /proc/${PID}/limits | grep "Max open files"
-
檢視程式當前開啟的檔案描述符數。
lsof -p ${PID} | wc -l
-
調整程式的最大檔案描述符數。
從 CentOS 6 開始,支援線上調整程式的最大檔案描述符數,無需重啟程式。
#CentOS 6 echo -n "Max open files=102400:102400" > /proc/${PID}/limits #CentOS 7 prlimit --pid ${PID} --nofile=102400:102400
注意,CentOS 6 的調整方式在 CentOS 7 中不適用,同樣,CentOS 6 中也不支援 prlimit 命令。
這就意味著,後續MySQL出現“Too many open files”錯誤,再也不用重啟程式了。
如果系統不支援線上調整程式的最大檔案描述符數。就只能修改配置,重啟例項。具體步驟如下:
-
首先檢視程式的啟動使用者。
ps -ef | grep mysqld
獲取 mysqld 父程式的 ID(PPID),對應輸出的第三列。
基於 PPID 檢視 mysqld 的父程式。
ps -ef | grep ${PPID}
第一列顯示的使用者就是啟動使用者。
-
修改啟動使用者可開啟的最大檔案描述符數。
vim /etc/security/limits.conf
-
修改 open_files_limit 的配置,重啟例項。
無論是線上,還是通過/etc/security/limits.conf,調整程式的最大檔案描述符數,在調整的時候,注意以下幾點:
-
程式的最大檔案描述符數不能超過/proc/sys/fs/nr_open 的大小。
-
如果修改了/proc/sys/fs/nr_open,需同步修改/proc/sys/fs/file-max,後者代表了核心能分配的最大檔案描述符數。
-
為了保證配置在系統重啟後依然有效,建議同步修改/etc/sysctl.conf。
# vim /etc/sysctl.conf fs.nr_open=100000 fs.file-max=100000 # sysctl -p
五、檢視程式當前開啟的檔案描述符數
在 MySQL 狀態變數中,沒有能直觀反映檔案描述符的指標。
看下面這個 Demo。
open_files_limit 等於 1024,當檔案描述符不足,出現“Too many open files”錯誤時,mysql 狀態變數及 lsof 的統計結果如下:
mysql> show global status where variable_name like 'open%' or variable_name='innodb_num_open_files'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | Innodb_num_open_files | 431 | | Open_files | 2 | | Open_streams | 0 | | Open_table_definitions | 615 | | Open_tables | 578 | | Opened_files | 1303 | | Opened_table_definitions | 1260 | | Opened_tables | 1928 | +--------------------------+-------+ 8 rows in set (0.00 sec) mysql> select @@open_files_limit,@@innodb_open_files; +--------------------+---------------------+ | @@open_files_limit | @@innodb_open_files | +--------------------+---------------------+ | 1024 | 431 | +--------------------+---------------------+ 1 row in set (0.01 sec)
其中,
-
Innodb_num_open_files:InnoDB 當前開啟的檔案數。InnoDB 同時能開啟的最大檔案數由 innodb_open_files 引數決定,後者預設為-1,基於 table_cache_size 自動調整。
innodb_open_files 並不是一個硬限制。如果 InnoDB 開啟的檔案數達到了 innodb_open_files 的限制,則會通過 LRU 演算法關閉其它檔案。
if (innobase_open_files < 11) { innobase_open_files = 300; if (srv_file_per_table && table_cache_size > 300) { innobase_open_files = table_cache_size; } } if (innobase_open_files > (long) open_files_limit) { ib::warn() << "innodb_open_files should not be greater" " than the open_files_limit.\n"; if (innobase_open_files > (long) table_cache_size) { innobase_open_files = table_cache_size; } }
-
Open_files:當前開啟的檔案數。
-
Opened_files:開啟過的檔案數。
從輸出結果來看,這三個變數的值與 open_files_limit(1024)相去甚遠,不如 lsof 的準確。
[root@node1 ~]# lsof -p 9020 | wc -l 1054
其中,9020 是程式的 PID。
lsof 同樣適用於其它程式的統計。
六、總結
-
open_files_limit 會取以下三個值中的最大值。
- limit_1 = 10 + max_connections + table_cache_size * 2。
- limit_2 = max_connections * 5。
- limit_3 = open_files_limit ? open_files_limit : 5000。
如果程式的最大檔案描述符數超過 open_files_limit,則實際生效的的是程式的最大檔案描述符數。
如果程式的最大檔案描述符數小於 open_files_limit,需區分啟動使用者。
3.1 如果啟動使用者是 root,則實際生效的是 open_files_limit。
3.2 如果啟動使用者是普通使用者。
- open_files_limit 小於等於硬限制,則實際生效的是 open_files_limit。
- open_files_limit 大於硬限制,則實際生效的是程式的最大檔案描述符數。
如果程式是通過 mysqld_safe 啟動的,則 mysqld_safe 會基於 open_files_limit 調整程式的最大檔案描述符數。
在原始碼裡,其實還區分了一個場景,即最大檔案描述符數為 unlimited。但實際上,在 RHEL 及其衍生版本中,不允許將 nofile 設定為 unlimited。
# ulimit -n unlimited
-bash: ulimit: open files: cannot modify limit: Operation not permitted
雖然允許在/etc/security/limits.conf 檔案中將 nofile 設定為 unlimited,但效果等同於 0,此時,相關使用者不能建立新的程式,也不允許登入。
# su - mysql su: cannot open session: Permission denied # ssh mysql@192.168.244.10 Connection to 192.168.244.10 closed.
在調整程式的最大檔案描述符數時,注意:單個程式的最大檔案描述符數 <= fs.nr_open <= fs.file-max
從 CentOS 6 開始,可線上調整程式的最大檔案描述符數,無需重啟程式。
七、參考資料
https://man7.org/linux/man-pages/man2/getrlimit.2.html
https://www.ibm.com/docs/en/sdk-java-technology/7?topic=rja-system-resource-limits-ulimit-command