最近项目准备上线,在测试环境测试通过,准备把项目部署到『预发布环境』,可以把它理解为我们上线前的最后一个验证环境。在部署的过程中,发现涉及的几个项目都部署失败了,jenkins 集成平台上『一片报红』,把我给整懵逼了。
这里再交代一下项目部署的方式:通过 jenkins 进行一系列 build 相关的操作之后,将构建产物(war包形式)传输到指定环境机器的 tomcat 容器中,启动运行。
赶紧把机器上 tomcat 日志拉下来看一波,很快发现对应的几个项目虽然都成功部署到了容器当中,但是启动过程都失败了。
看日志应该是在解压 jar 包的过程中遇到了问题,显示 【Too many open files】,从字面上理解应该是和当前机器打开的文件数量有关。
这里就要引出 linux 文件句柄的概念了, 句柄可以理解为一个特殊标识,经过操作系统的处理之后,可以指向一块内存区域,听起来有点像『指针』,区别在于指针是直接指向内存,而句柄则是依赖于操作系统或者其它程序的处理之后,重定向到某块内存区域 。
这边只需要理解,应用进程操作文件需要通过操作系统提供的句柄对象。
文件句柄既然由操作系统提供, linux系统当然不会让你无休止打开文件,它对单个进程允许打开的句柄数进行了限制。
通过 ulimit -a 命令可以查看到所有系统资源限制参数,其中 open files 行就是当前允许单个进程打开的最大句柄数,为65535。
[root@iZ8vbcrus31oj4g007u7b0Z ~]# ulimit -a core file size (blocks, -c) unlimited data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 6871 max locked memory (kbytes, -l) 16384 max memory size (kbytes, -m) unlimited open files (-n) 65535 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 6871 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited 复制代码
当然也可以直接通过 ulimit -n 查看句柄限制。
[root@iZ8vbcrus31oj4g007u7b0Z ~]# ulimit -n 65535 复制代码
接下来我们查看某个进程打开的文件数。
通过 ps 命令,先找到对应进程的 PID,例如 mysql 服务进程。
[root@iZ8vbcrus31oj4g007u7b0Z ~]# ps -ef | grep 'mysql' UID PID PPID C STIME TTY TIME CMD mysql 1058 1 0 4月05 ? 00:17:36 /usr/sbin/mysqld 复制代码
之后通过 lsof 命令可以查看指定进程打开的文件详情,再对结果进行统计,以此得到某个进程打开的文件数,可以看到我机器上的 mysql 服务当前打开的文件数为 77
[root@iZ8vbcrus31oj4g007u7b0Z ~]# lsof -p 1058 | wc -l 77 复制代码
可以重新配置的这个句柄限制数,可以看到默认给 root 用户配置了限制数为 65535,即这个限制是针对 root 用户打开的进程。
vi /etc/security/limits.conf 复制代码
不指定登录用户,则是针对于所有用户进行的限制。
soft nofile 65535 hard nofile 65535 复制代码
注意,修改配置后需要断开 ssh 连接,重新登录,配置才会生效。