我的应用程序基于两个通过 http 连接交换数据的 Java 进程,运行文件并产生以下错误消息:
Aug 14 11:27:40 server sender[8301]: java.io.IOException: Too many open files
Aug 14 11:27:40 server sender[8301]: at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
Aug 14 11:27:40 server sender[8301]: at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422)
Aug 14 11:27:40 server sender[8301]: at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250)
Aug 14 11:27:40 server sender[8301]: at org.apache.tomcat.util.net.NioEndpoint$Acceptor.run(NioEndpoint.java:455)
Aug 14 11:27:40 server sender[8301]: at java.lang.Thread.run(Thread.java:748)
这两个进程都在 SystemD 的控制之下。我使用检查了进程cat /proc/5882/limits
,限制定义如下:
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 8388608 unlimited bytes
Max core file size 0 unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 63434 63434 processes
Max open files 4096 4096 files
Max locked memory 65536 65536 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 63434 63434 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 0 0
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us
当我运行时,lsof | grep pid | wc -l
我的条目少于 2000 个(我以这种方式运行 lsof 因为从尝试获取每个进程打开文件的计数时与 lsof 命令存在差异)
我完全不知道我可以进一步检查或增加什么。
答案1
判断进程有多少个打开的文件描述符的最佳方法是使用:
$ ls /proc/8301/fd/ | wc -l
(假设 PID 8301,就像您的日志中一样。)
运行lsof
将遍历整个/proc
树,并尝试解析所有文件的名称(这些是伪符号链接,需要调用每个文件的 readlink 进行解析),因此运行lsof
将花费很长时间(取决于您的计算机的繁忙程度),所以当你看到结果时,可能一切都已经改变了。使用起来ls /proc/${pid}/fd/
会很快(只需一次 readdir 调用),因此更有可能捕获接近当前情况的内容。
关于解决问题,您可能需要考虑增加服务允许的文件描述符的数量,您可以通过设置 LimitNOFILE=
指令在你的 systemd 单元文件中。