limits.conf的工作原理:
limits.conf的后端是这样工作的:limits.conf是 pam_limits.so的配置文件,然后/etc/pam.d/下的应用程序
调用pam_***.so模块。譬如说,当用户访问服务器,服务程序将请求发送到PAM模块,PAM模块根据服务名称在/etc/pam.d目录下选择一个对应的服务文件,然后根据服务文件的内容选择具体的PAM模块进行处理。[摘抄]
ulimit是一种简单并且有效的实现系统资源限制的方式!
下面分享一个小实验!
实验:limits实验!关于能打开的最大文件数和能并发的最大进程数:
[研究背景: nginx 与 php 的连接, 以及对其做压力测试的时候! 由于php-cgi是单进程的,影响nginx的效率, 然后便使用产蛋程序 spawn.但是它依然受到限制, 怎么办? 系统最大并发进程数的控制, 也就是下面实验的目的了! ]
[注意, 先将系统的默认全局参数调大 sysctl.conf -->kernel.threads-max = xxxxx .... ]
实验结论:
a. nofile的配置,可以用 * 来通配对所有的用户的设置!
b. noproc的配置,用 * 无法通配, 只能指定特定的用户!
温馨提醒: 最大进程并发数的设置很危险的,如果你的机器性能不是很好的话,用spawn产出5000个cgi进程,然后用ab并发出上万个查询请求进行压力测试!最后你发现,并发数小于5000的时候错误率为零,再高点儿,就有错了! [当然,我使用的是台PC机,不是标配的服务器! 实践很重要!]
另外,当要killall全杀掉服务端开启的cgi进程,你会发现机器卡了,我的实验机器性能不怎么好,崩掉啦~
1> limits.conf:
--------------------------->
* soft nofile 1000000
* hard nofile 1000000
root soft nproc 20000
root hard nproc 20000
* soft nproc 20000
* hard nproc 20000
---------------------------->
实验结果:
[root@lin /]# ulimit -u //20000
[root@lin /]# ulimit -n //1000000
[root@lin /]# su - test
[test@lin ~]$ ulimit -u //1024
[test@lin ~]$ ulimit -n //1000000
####################################
2> limits.conf
--------------------------->
* soft nofile 1000000
* hard nofile 1000000
root soft nproc 20000
root hard nproc 20000
* soft nproc 20000
* hard nproc 20000
test soft nproc 20000
test hard nproc 20000
---------------------------->
实验结果:
[root@lin /]# ulimit -u //20000
[root@lin /]# ulimit -n //1000000
[root@lin /]# su - test
[test@lin ~]$ ulimit -u //20000
[test@lin ~]$ ulimit -n //1000000
######################################
3> limits.conf
---------------------------->
* soft nofile 1000000
* hard nofile 1000000
root soft nproc 30000
root hard nproc 30000
----------------------------->
实验结果:
[root@lin /]# su - root
[root@lin ~]# ulimit -u //30000
[root@lin ~]# ulimit -n //1000000
[root@lin /]# su - test
[test@lin ~]$ ulimit -u //1024
[test@lin ~]$ ulimit -n //1000000
#######################################
4> limits.conf
------------------------------>
* soft nofile 1000000
* hard nofile 1000000
* soft nproc 20000
* hard nproc 20000
------------------------------->
实验结果:
[root@lin /]# su - root
[root@lin ~]# ulimit -u //1024
[root@lin ~]# ulimit -n //1000000
[root@lin ~]# su - test
[test@lin ~]$ ulimit -u //1024
[test@lin ~]$ ulimit -n //1000000
########################################
Appendix:
ulimit是shell内建命令,贴出它的manual手册:
===================================================================================
ulimit [-HSTabcdefilmnpqrstuvx [limit]]
Provides control over the resources available to the
shell and to processes started by it, on systems that
allow such control. The -H and -S options specify that
the hard or soft limit is set for the given resource.
A hard limit cannot be increased by a non-root user
once it is set; a soft limit may be increased up to the
value of the hard limit. If neither -H nor -S is spec-
ified, both the soft and hard limits are set. The
value of limit can be a number in the unit specified
for the resource or one of the special values hard,
soft, or unlimited, which stand for the current hard
limit, the current soft limit, and no limit, respec-
tively. If limit is omitted, the current value of the
soft limit of the resource is printed, unless the -H
option is given. When more than one resource is speci-
fied, the limit name and unit are printed before the
value. Other options are interpreted as follows:
-a All current limits are reported
-b The maximum socket buffer size
-c The maximum size of core files created
-d The maximum size of a process’s data segment
-e The maximum scheduling priority ("nice")
-f The maximum size of files written by the shell
and its children
-i The maximum number of pending signals
-l The maximum size that may be locked into memory
-m The maximum resident set size (many systems do
not honor this limit)
-n The maximum number of open file descriptors
(most systems do not allow this value to be set)
-p The pipe size in 512-byte blocks (this may not
be set)
-q The maximum number of bytes in POSIX message
queues
-r The maximum real-time scheduling priority
-s The maximum stack size
-t The maximum amount of cpu time in seconds
-u The maximum number of processes available to a
single user
-v The maximum amount of virtual memory available
to the shell
-x The maximum number of file locks
-T The maximum number of threads
If limit is given, it is the new value of the specified
resource (the -a option is display only). If no option
is given, then -f is assumed. Values are in 1024-byte
increments, except for -t, which is in seconds, -p,
which is in units of 512-byte blocks, and -T, -b, -n,
and -u, which are unscaled values. The return status
is 0 unless an invalid option or argument is supplied,
or an error occurs while setting a new limit.
=====================================================================================
转一个绝对牛掰的过来:(2013年6月加)
前两天微博上的@王关胜同学问了个问题:
#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的问题的解决,参见 这里
我们来简单的做下实验:
$ cat /etc/security/limits.d/90-nproc.conf |
$ cat /etc/security/limits.d/90-nproc.conf |
我们可以看出就是说当注释掉限制的话,不同的机器值是不同的。
我们先来回答第一个问题:为什么limit配置文件是 /etc/security/limits.d/90-nproc.conf 而不是其他
这个问题早些时候 杨德华 同学碰到了,也写了篇 博文 来解释redhat6下面如何破解nproc的限制,但是文章没提到这个问题。
我们一步步来看这个问题,首先看下 谁在使用 90-nproc.conf 这个文件:
probe syscall. open . return { |
filename = user_string($filename) |
if (!isinstr(filename, "90-nproc.conf" )) next; |
printf ( "%s %d\n" , execname(), pid()); |
运行脚本后,开个ssh终端上去,就马上知道sshd在使用这个文件, 同时也验证了配置是即刻生效的。
我们都知道linux下这个limit限制是由pam_limits来执行的。
那么什么是PAM以及它的架构,参考 这里
$ 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就知道 限制如何执行的:
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" ); |
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)); |
if (retval != PAM_SUCCESS || pl->conf_file != NULL) |
oldlocale = setlocale (LC_COLLATE, "C" ); |
glob_rc = glob(LIMITS_CONF_GLOB, GLOB_ERR, NULL, &globbuf); |
setlocale (LC_COLLATE, oldlocale); |
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)); |
if (retval != PAM_SUCCESS) |
分析这段代码可以知道先读/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:
/home/chuba/linux-2.6.18.x86_64/kernel |
./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;
我们来验证下:
$ cat /proc/meminfo | grep MemTotal |
$ echo "49421024 / 128" | bc |
算出来default_nproc =386101 是不是和实际的很接近?
因为物理页面会内存用作一些关键数据,所以实际的比计算出来的要小点。
小结: 源码说话!
祝玩的开心!