ulimit限制之nproc问题

淘宝核心系统团队博客 | ulimit限制之nproc问题

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\n", 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 是不是和实际的很接近?
因为物理页面会内存用作一些关键数据,所以实际的比计算出来的要小点。

小结: 源码说话!

祝玩的开心!

posted on 2013-03-28 20:13 lexus 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lexus/archive/2013/03/28/2987449.html

ulimit限制之nproc问题相关推荐

  1. ulimit问题 关于nproc设置

    #ulimit问题# 关于nproc设置:centos6,内核版本是2.6.32. 默认情况下,ulimit -u的值为1024,是/etc/security/limits.d/90-nproc.co ...

  2. c10k问题及其解决方案

    本文主要讲述高并发http应用中的c10k瓶颈问题:在很多服务器初始状态下,无法服务1w左右的并发连接.这与每次服务的资源消耗.服务器的硬件配置固然有关,但很多时候是被linux的默认配置以及软件st ...

  3. Docker(八):Docker Compose

    Docker Compose Compose 简介 Compose 是用于定义和运行多容器 Docker 应用程序的工具.通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务.然 ...

  4. mysql backlog_一次优化引发的血案

    前些天一个Nginx+PHP项目上线后遭遇了性能问题,于是打算练练手,因为代码并不是我亲自写的,所以决定从系统层面入手看看能否做一些粗线条的优化. 首先,我发现服务的Backlog设置过小,可以通过s ...

  5. Docker容器中MySQL最大连接数被限制为214的解决方案

    Docker容器中MySQL最大连接数被限制为214的解决方案 原文:Docker容器中MySQL最大连接数被限制为214的解决方案 一.背景 话说笔者在上次的博客里简单的讲了一下调整MySQL最大连 ...

  6. docker-compose(入门,与docker的区别)

    Compose 简介 Compose 是用于定义和运行多容器 Docker 应用程序的工具.通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务.然后,使用一个命令,就可以从 Y ...

  7. Oracle 12cR1 RAC 在VMware Workstation上安装(上)—OS环境配置

    Oracle 12cR1 RAC 在VMware Workstation上安装(上)-OS环境配置 1.1  整体规划部分 1.1.1  所需软件介绍 Oracle RAC不支持异构平台.在同一个集群 ...

  8. Ubuntu安装Elasticsearch集群及Kibana

    1, 下载ES及Kibana https://www.elastic.co/cn/downloads/elasticsearch https://www.elastic.co/cn/downloads ...

  9. docker 单节点服务编排部署指南(docker-compose)

    Docker-Compose 多容器部署工具 概述 Docker-Compose 项目是 Docker 官方的开源项目,是用于定义和运行多容器 Docker 应用程序的工具.负责实现对 Docker ...

最新文章

  1. 哲学是什么?(选自:苏菲的世界)
  2. 28岁适合转嵌入式开发吗?
  3. C语言基础之--scanf函数
  4. php7怎么开pdo,linux php7.2开启pdo等扩展
  5. Spring – Sending E-Mail Via Gmail SMTP Server With MailSender--reference
  6. 运输pascal 90分程序
  7. jQuery常用的方法
  8. ADO.NET学习笔记--数据汇总(聚合函数)
  9. 黑马程序员_MapK,V 映射关系 Map.Entry
  10. Julia:关于push 与 Array 和Dict 数据结构
  11. 【预测模型】基于matlab GUI BP神经网络+最小二乘法预测模型【含Matlab源码 208期】
  12. 【机器学习|数学基础】Mathematics for Machine Learning系列之线性代数(1):二阶与三阶行列式、全排列及其逆序数
  13. 线程的状态及状态转换
  14. 梦之光芒Monyer (全关解析)
  15. 转换质量分数与摩尔分数
  16. 你是否在Microsoft Edge上测试你的网站?
  17. 幼儿园计算机技能大赛,幼儿园教师技能大赛的心得体会.docx
  18. 女生要不要去北航学计算机,在北航读书有个女朋友是种怎样的体验?
  19. 【Alpha】阶段第九次Scrum Meeting
  20. linux opencv 显示视频文件夹,opencv cvCaptureFromFile读取视频问题汇总

热门文章

  1. Bookshop Memories
  2. 马尾综合征能恢复到什么地步
  3. 前端利用canvas实现手写板
  4. 蓄能电源PSE认证,CE认证,FCC认证,ROHS认证
  5. webgl火焰特效(证实可用)
  6. 目标检测SSD学习笔记
  7. sql数据库教程百度云_【推荐】板绘初学者先练什么?ps板绘教程零基础百度云下载!...
  8. BootStrap-CSS样式_插件_工具提示(Tooltip)插件
  9. 阿里云对象存储oss依赖报错
  10. 如何把一个锅刷成电影质感?【转】