IO例外:開いているファイルが多すぎます
-
20-09-2019 - |
質問
Linux 上の Jetty 7.0.1 で実行されている Java Web アプリでのファイル記述子のリークをデバッグしようとしています。
アプリは 1 か月ほど問題なく実行されていましたが、次の理由でリクエストが失敗し始めました。 開いているファイルが多すぎます, 、Jettyを再起動する必要がありました。
java.io.IOException: Cannot run program [external program]: java.io.IOException: error=24, Too many open files
at java.lang.ProcessBuilder.start(ProcessBuilder.java:459)
at java.lang.Runtime.exec(Runtime.java:593)
at org.apache.commons.exec.launcher.Java13CommandLauncher.exec(Java13CommandLauncher.java:58)
at org.apache.commons.exec.DefaultExecutor.launch(DefaultExecutor.java:246)
最初は、外部プログラムを起動するコードに問題があるのではないかと思いましたが、 コモンズエグゼクティブ それに何も問題はありません:
CommandLine command = new CommandLine("/path/to/command")
.addArgument("...");
ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream();
Executor executor = new DefaultExecutor();
executor.setWatchdog(new ExecuteWatchdog(PROCESS_TIMEOUT));
executor.setStreamHandler(new PumpStreamHandler(null, errorBuffer));
try {
executor.execute(command);
} catch (ExecuteException executeException) {
if (executeException.getExitValue() == EXIT_CODE_TIMEOUT) {
throw new MyCommandException("timeout");
} else {
throw new MyCommandException(errorBuffer.toString("UTF-8"));
}
}
サーバー上で開いているファイルをリストすると、多数の FIFO があることがわかります。
# lsof -u jetty
...
java 524 jetty 218w FIFO 0,6 0t0 19404236 pipe
java 524 jetty 219r FIFO 0,6 0t0 19404008 pipe
java 524 jetty 220r FIFO 0,6 0t0 19404237 pipe
java 524 jetty 222r FIFO 0,6 0t0 19404238 pipe
Jetty が起動したとき、FIFO はわずか 10 個でしたが、数日後には数百個になりました。
この段階では少し曖昧だとは思いますが、次にどこを調べればよいか、またはそれらのファイル記述子に関するより詳細な情報を取得する方法について何か提案はありますか?
解決
あなたの外部プログラムが正常に動作しません。それはそれをしない理由を見てみましょう。
他のヒント
問題は Java アプリケーション (または使用しているライブラリ) に起因します。
初め, 、出力全体 (StreamGobbler については Google) を読んでください。
Javadoc 言います:
親プロセスは、これらのストリームを使用して、サブプロセスから入力をフィードし、出力を取得します。一部のネイティブプラットフォームは、標準の入力ストリームと出力ストリームに限られたバッファサイズのみを提供するため、入力ストリームを迅速に書き込んだり、サブプロセスの出力ストリームを読み取ったりしないと、サブプロセスがブロックされたり、デッドロックさえしたりする可能性があります。
第二に, waitFor()
プロセスを終了します。次に、入力、出力、およびエラー ストリームを閉じる必要があります。
ついに destroy()
あなたのプロセス。
私の情報源:
私はあなたのファイル記述子が不足している疑いがあります。 ulimitのをチェックしてください。 ます。http:ここでは、問題を説明する記事です://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/する
は、あなたのアプリの本質を知らないが、私はこのエラーが原因で接続プールリークの複数回現れ、そのためにはチェックアウトする価値があるだろう見てきました。 Linuxでは、ソケット接続は、ファイル記述子だけでなく、ファイル・システムのファイルを消費します。ただ、考えています。
ほかに「開いているファイル」の制限を正当な増加を行うと、編集を検討し、リブート後その持っているために、ファイル等の漏洩、などの根本的な原因の問題を検討してから
/etc/security/limits.conf
このような何かを追加することにより、
jetty soft nofile 2048
jetty hard nofile 4096
ここで、「桟橋」は、この場合のユーザ名です。 limits.confをの詳細については、 http://linux.die.net/manを見ます/5/limits.confする
ログオフし、再度ログインして、実行します。
ulimit -n
変更が行われたことを確認します。このユーザーによる新しいプロセスが今、この変更に従うべきです。 このリンクには、すでに実行中のプロセスに制限を適用する方法を説明しているようだが、私それを試していません。
デフォルトの制限値1024は、大規模なJavaアプリケーションのための低すぎることができます。
あなたはFDSを自分で処理することができます。 JavaでExecは、プロセスオブジェクトを返します。プロセスがまだ実行されている場合は断続的に確認してください。それが近いプロセスSTDERR、STDINおよびSTDOUTストリームを完了すると(例えばproc.getErrorStream.close())。それは漏れを軽減します。
あなたは、同時に多くのファイルにデータを書き込んでいる場合、この問題が来ると、あなたのオペレーティングシステムは、オープンファイルの一定の制限があります。 Linuxでは、あなたは、開いているファイルの上限を増やすことができます。