ulimit限制之nproc问题
Posted swchswhih
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ulimit限制之nproc问题相关的知识,希望对你有一定的参考价值。
前两天微博上的@王关胜同学问了个问题:
#ulimit问题# 关于nproc设置:centos6,内核版本是2.6.32. 默认情况下,ulimit -u的值为1024,是/etc/security/limits.d/90-nproc.conf的值限制;注释掉这个限制后,值为95044;手工设置90-nproc.conf文件,值为新设置的值。想请 问这个95044是怎么来的?
这个问题挺有意思的,这里面有二个信息点:
1. 为什么limit配置文件是 /etc/security/limits.d/90-nproc.conf 而不是其他?
2. 为什么是nproc的值95044,而不是其他。
之前我也写了些ulimit的问题的解决,参见 这里
我们来简单的做下实验:
1
2
3
4
5
6
7
8
9
|
$ cat
/etc/security/limits .d /90-nproc .conf
* soft nproc 8933 $ ulimit
-u 8933 $ cat
/etc/security/limits .d /90-nproc .conf
#注释掉 #* soft nproc 8933 $ ulimit
-u 385962 |
我们可以看出就是说当注释掉限制的话,不同的机器值是不同的。
我们先来回答第一个问题:为什么limit配置文件是 /etc/security/limits.d/90-nproc.conf 而不是其他
这个问题早些时候 杨德华 同学碰到了,也写了篇
博文 来解释redhat6下面如何破解nproc的限制,但是文章没提到这个问题。
我们一步步来看这个问题,首先看下 谁在使用 90-nproc.conf 这个文件:
1
2
3
4
5
6
7
8
|
$ cat
t.stp probe syscall. open . return
{ filename = user_string($filename) if
(!isinstr(filename, "90-nproc.conf" )) next; printf ( "%s %d
" , execname(), pid()); } $ sudo
stap t.stp sshd 24844 |
运行脚本后,开个ssh终端上去,就马上知道sshd在使用这个文件, 同时也验证了配置是即刻生效的。
我们都知道linux下这个limit限制是由pam_limits来执行的。
那么什么是PAM以及它的架构,参考 这里
1
2
3
4
5
6
7
8
9
10
11
12
|
$ grep
-rin pam_limit /etc/pam .d /etc/pam .d /sudo-i :6:session required pam_limits.so /etc/pam .d /smartcard-auth-ac :16:session required pam_limits.so /etc/pam .d /smartcard-auth :16:session required pam_limits.so /etc/pam .d /system-auth-ac :20:session required pam_limits.so /etc/pam .d /fingerprint-auth :16:session required pam_limits.so /etc/pam .d /sudo :6:session required pam_limits.so /etc/pam .d /runuser :4:session required pam_limits.so /etc/pam .d /password-auth-ac :19:session required pam_limits.so /etc/pam .d /password-auth :19:session required pam_limits.so /etc/pam .d /system-auth :20:session required pam_limits.so /etc/pam .d /fingerprint-auth-ac :16:session required pam_limits.so |
那很自然,我们就会去找pam_limits的代码来看, 代码在 这里 可以下载,目前的版本是 Linux-PAM-1.1.6。
瞄几下modules/pam_limits/pam_limits.c就知道 限制如何执行的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
/* now the session stuff */ PAM_EXTERN int pam_sm_open_session (pam_handle_t *pamh,
int flags UNUSED, int
argc, const
char **argv) { [...] retval = init_limits(pamh, pl, ctrl); if
(retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_WARNING,
"cannot initialize" ); return
PAM_ABORT; }
retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl); if
(retval == PAM_IGNORE) { D(( "the configuration file (‘%s‘) has an applicable ‘<domain> -‘ entry" , CONF_FILE)); return
PAM_SUCCESS; } if
(retval != PAM_SUCCESS || pl->conf_file != NULL) /* skip reading limits.d if config file explicitely specified */ goto
out; /* Read subsequent *.conf files, if they exist. */ /* set the LC_COLLATE so the sorting order doesn‘t depend
on system locale */ oldlocale =
setlocale (LC_COLLATE,
"C" ); glob_rc = glob(LIMITS_CONF_GLOB, GLOB_ERR, NULL, &globbuf); if
(oldlocale != NULL) setlocale
(LC_COLLATE, oldlocale); if
(!glob_rc) { /* Parse the *.conf files. */ for
(i = 0; globbuf.gl_pathv[i] != NULL; i++) { pl->conf_file = globbuf.gl_pathv[i]; retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl); if
(retval == PAM_IGNORE) { D(( "the configuration file (‘%s‘) has an applicable ‘<domain> -‘ entry" , pl->conf_file)); globfree(&globbuf); return
PAM_SUCCESS; } if
(retval != PAM_SUCCESS) goto
out; } } out: [...] } |
分析这段代码可以知道先读/etc/security/limits.conf,如果/etc/security/limits.d/目录下还有配置文件的话,也读进来,一起分析。
这就意味/etc/security/limits.d/里面的文件里面的配置会覆盖/etc/security/limits.conf的配置。
我们看下这行:glob_rc = glob(LIMITS_CONF_GLOB, GLOB_ERR, NULL, &globbuf);
读取/etc/security/limits.d/目录下文件的函数,从名字就可以猜出,是遍历,文件名的数字起到顺序的作用。
到此就解释了文件名90-nproc.conf的作用。
接着看第二个问题: 为什么是nproc的值95044, 而不是其他。
通过阅读process_limit函数只是看到 nproc的最大值限制,没有看到其他的,那我们就很容易联想,如果用户不设置nproc的话,那么这个值应该是由内核自己来决定。
我们看下内核代码 2.6.18:
1
2
3
4
5
6
7
8
9
10
11
|
$ pwd /home/chuba/linux-2 .6.18.x86_64 /kernel $ grep
-rin nproc . . /sys .c:896: current->signal->rlim[RLIMIT_NPROC].rlim_cur && . /fork .c:176: init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads /2 ; . /fork .c:177: init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads /2 ; . /fork .c:179: init_task.signal->rlim[RLIMIT_NPROC]; . /fork .c:1130: p->signal->rlim[RLIMIT_NPROC].rlim_cur) { . /cpuset .c:69: int cnt; /* unprocessed events count */ . /cpuset .c:1140: * Limit the count of unprocessed events to FM_MAXCNT, so as to avoid . /user .c:181: * new uid over his NPROC rlimit? We can check this now |
一下子就看出来了 默认值是 max_threads/2. 打开fork.c分析下:
//fork_init(num_physpages);
//void __init fork_init(unsigned long mempages)
/*
* The default maximum number of threads is set to a safe
* value: the thread structures can take up at most half
* of memory.
*/
max_threads = mempages / (8 * THREAD_SIZE / PAGE_SIZE);
其中mempages是机器的物理页面个数, THREAD_SIZE=8K, 也就是说:
default_nproc = max_threads / 2 = (mempages * PAGE_SIZE) / ( 2 * 8 *THREAD_SIZE ) = total_memory/128K;
我们来验证下:
1
2
3
4
5
6
|
$ cat
/proc/meminfo | grep
MemTotal MemTotal: 49421024 kB $ echo
"49421024 / 128" |
bc 386101 $ ulimit
-u 385962 |
算出来default_nproc =386101 是不是和实际的很接近?
因为物理页面会内存用作一些关键数据,所以实际的比计算出来的要小点。
小结: 源码说话!
祝玩的开心!
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://www.cnblogs.com/captainbed
以上是关于ulimit限制之nproc问题的主要内容,如果未能解决你的问题,请参考以下文章