我的应用程序基于两个通过 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 是因为在尝试获取每个进程的打开文件数时从 Discrepancy with lsof 命令检索到的信息)
我不知道我可以检查或进一步增加什么。
判断您的进程有多少打开文件描述符的最佳方法是使用:
(假设 PID 8301,就像在你的日志中一样。)
运行
lsof
将遍历整个/proc
树并尝试解析所有文件的名称(这些是伪符号链接,需要调用 readlink 来解析每个文件),因此运行lsof
将需要很长时间(取决于您的机器有多忙),因此,当您查看结果时,可能一切都已经改变了。使用ls /proc/${pid}/fd/
会很快(只有一次 readdir 调用),因此更有可能捕获接近当前情况的内容。关于解决这个问题,您可能需要考虑增加允许您的服务使用的文件描述符的数量,您可以通过在 systemd 单元文件中设置
LimitNOFILE=
指令来做到这一点。