ulimit到底谁说了算?

最近在用nginx+PHP FastCGI(php-fpm)配置站点(php-fpm默认的文件打开数目如果不做规定,就是系统最大数目,也就是只要修改系统数目就好了),在最后阶段的优化过程中发现这ulimit的问题很奇怪,那就是/etc/security/limits.conf这个文件说了不算!
如下是我的配置文件

* soft nofile 65530
* hard nofile 65530

可以看见 软硬限制都是已经写到65530,但是重启后运行ulimit -n查看,还是默认1024
再Google上查阅资料,有人说看见ulimit -n变了才算是生效,有人说得看 cat /proc/{pid}/limits |grep 'Max open files'
经过多方求证,发现第二种方法才是最正确的方法,这里面真复杂。
根据IBM知识库

作为临时限制,ulimit 可以作用于通过使用其命令登录的 shell 会话,在会话终止时便结束限制,并不影响于其他 shell 会话。而对于长期的固定限制,ulimit 命令语句又可以被添加到由登录 shell 读取的文件中,作用于特定的 shell 用户。

这里没有提及/etc/security/limits.conf,因为这个配置文件起效必须基于pam验证,且PAM 的 limits 模块要启用。在我配置过程中,我已经都启用了,但是无论我怎么重启服务器,就是不生效。具体原因不详。
例外,文章所说的ulimit是作为一种“临时限制”来存在的。我来举个例子。假设我开了一个用户root登录shell A,设置ulimit -SHn 65535,这个用户启动了程序A(比如nginx),当用户退出shell A后A程序继续工作在65535个文件打开限制。这时候,当用户root登录到shell B,查看ulimit -n 还是1024个 查看(self是到当前程序 PID的软连接)

cat /proc/self/limits |grep 'Max open files'

看到的是一样的。

下面我们来获取程序A(nginx)的pid,查看他的limits

显示

Max open files 65530 65530 files
Max open files 65530 65530 files
Max open files 65530 65530 files
Max open files 65530 65530 files

可见A程序(nginx)工作限制和当前用户所在地shell的限制无必然关系。推而广之,要想真正让nginx和php5-fpm工作在最大打开文件数目模式下,编辑他们的init.d内地文件,开头加上ulimit -SHn 65535即可
可是这样一两个程序还可以,要是多个程序呢?有人说写到rc.local/profile里面,我也测试了
首先我在profile里面设立了自己的ulimit,重启后进入shell查看,确实是65530,/proc/self/limits也是。那么nginx的运行状况如何呢?
还是用上面那个程序查看了一下,发现nginx还是工作在默认的1024限制下面,可见当前shell的ulimit和nginx工作的ulimit不相等(这种状况非常有迷惑性,误导了很多人,比如LNMP一键包就是加在profile里面的,这样的话,除非你手动登录上去重启nginx,否则他始终工作在1024的限制下面),那么写到rc.local结果如何呢?我测试了一下,除非你的nginx在rc.local里面启动,否则还是一样的结果(甚至更糟糕,所有不以是rc.local为父进程的程序都不能获得大的文件打开数目)。

说道这里问题的关键在于找到所有的程序的父进程,这个父进程有大文件数目打开权限,那么他的和他派生的子进程都会有大文件数目打开权限。但是我也不可能把所有的程序都赋予超大文件打开数目,会争夺资源。所以我的解决办法是rc.local调用一个shell脚本。这个脚本赋予大文件打开数目。然后再这个文件里面重新启动nginx/php-fpm/mysql等(不是reload,是restart.),同时为了自己在shell里面调试方便,profile里面也要设置。

当然这个只是折衷办法,要是能搞清/etc/security/limits.conf为何不生效就最好了。不知哪位可以解惑。


Update:
经过多次试验,好像终于有点明白了。

首先/etc/security/limits.conf里面的*默认是不匹配root用户的。你需要手动指定root才能在登录ssh后看见生效。
这个只在login这个动作发生的时候起作用。比如控制台登录等等。即使你修改了/etc/security/limits.conf使得通过控制台登录后看见ulimit -n生效了,但是nginx还是没有工作在那个大文件数目授权下面。因为启动nginx的时候是系统的服务管理器而不是你的会话。如果你一定要通过这种方式,你需要把nginx在你的会话里面重启一遍(不是reload 也不是reopen)nginx就能正常工作在你的大文件打开数目授权下了。

所以说,最保险的做法是什么?

我们把/etc/security/limits.conf恢复原状。把ulimit写在root的profile里面,这样是为了自己登录到会话后重新打开的nginx也能得到正确的授权。同时针对mysql/nginx/php-fpm/oracle等的launch程序做手脚,比如/etc/init.d/php5-fpm 的init程序做手脚。在里面加上ulimit语句,再比如自己编译的nginx 可以这样:新建一个/usr/local/bin/nginx脚本

。这样可以确保万无一失。

总之,判断成功与否标准是什么?

这个程序检测下来的数目和你期望的相当,而不是你在任何会话里面执行ulimit -n看到的结果。

Author Info :
  • From:ulimit到底谁说了算?
  • URL:https://blog.ihipop.info/2011/01/2053.html
  • Please Reserve This Link,Thanks!
  • 《ulimit到底谁说了算?》上有7条评论

    1. 从你的现象上判断,你的系统应该是debian/ubuntu,在这两个系统里,如果你修改/etc/security/limits.conf,类似
      * hard nofile 65530
      * soft nofile 65530
      的话,默认是对root不起作用,这个*会对除root用户外的其他用户生效
      如果你需要对root用户生效的话需要修改为
      root - nofile 65530
      其中-就代表了hard和soft,不用分开写的
      如果你系统是rhel/centos的话,
      * hard nofile 65530
      * soft nofile 65530
      是对所有用户生效包括root

      1. 嗯。这个我倒是没有仔细去测试。不过我现在觉得所有都程序开放很大的文件打开数也不好。所以我接受了debian的做法 在/etc/default里面定义需要修改文件打开数的程序的ulimit。
        debian打包者里面的很多包编写的init script都会载入这里对每个程序的定义的变量 在这里面定义ulimit就可以了
        话说文章里面我也说了 登录后看到的ulimit不一定是自启动程序所运行在的ulimit 还是得看procfs里面的句柄显示的内容才能最终确定,另外如果你当前shell是最大ulimit了 那么登录后在当前shell里面启动停止程序自然也是最大的ulimit了

    发表评论

    电子邮件地址不会被公开。 必填项已用*标注