LinuxのJetty 7.0.1で実行されているJava webappでファイル記述子リークをデバッグしようとしています。
開いているファイルが多すぎるためにリクエストが失敗し始めたと、Jettyを再起動する必要があったとき、アプリは1か月ほどうまく実行されていました。
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)
最初は、外部プログラムを起動するコードに問題があると思っていましたが、 commons-exec を使用しており、問題は見当たりません:
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が起動すると、わずか10個のFIFOがあり、数日後には数百個あります。
この段階では少しあいまいですが、次にどこを見るべきか、またはそれらのファイル記述子に関する詳細情報を取得する方法について何か提案はありますか?
外部プログラムが正しく動作しません。なぜそうしないのかを見てください。
問題は、Javaアプリケーション(または使用しているライブラリ))にあります。
最初に、出力全体(Google for StreamGobbler)、およびプロントを読む必要があります!
Javadoc 言う:
親プロセスはこれらのストリームを使用して、サブプロセスに入力を供給し、サブプロセスから出力を取得します。一部のネイティブプラットフォームは標準の入力および出力ストリームに限られたバッファサイズしか提供しないため、サブプロセスの入力ストリームの書き込みまたは出力ストリームの読み取りをすぐに失敗すると、サブプロセスがブロックされ、デッドロックさえ発生する場合があります。
二番目に、 waitFor()
終了するプロセス。その後、入力、出力、エラーストリームを閉じる必要があります。
最後にdestroy()
プロセス。
私の情報源:
Linuxで実行しているときに、ファイル記述子が不足していると思われます。 ulimitを確認してください。問題を説明する記事は次のとおりです。 http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/
「ファイルを開く」制限を合法的に増やし、再起動後も持続させるために、ファイルリークなどの根本原因の問題を調べることは別として、編集を検討してください。
/etc/security/limits.conf
このようなものを追加することにより
jetty soft nofile 2048
jetty hard nofile 4096
ここで、「jetty」はこの場合のユーザー名です。 limits.confの詳細については、 http://linux.die.net/man/5/limits.conf を参照してください
ログオフしてから再度ログインして実行する
ulimit -n
変更が行われたことを確認します。このユーザーによる新しいプロセスは、この変更に準拠する必要があります。 このリンク は、すでに実行中のプロセスに制限を適用する方法を説明しているようですが、試していません。
デフォルトの制限1024は、大きなJavaアプリケーションに対しては低すぎる可能性があります。
アプリの性質はわかりませんが、接続プールのリークが原因でこのエラーが何度も発生するのを確認したので、チェックする価値があります。 Linuxでは、ソケット接続はファイルシステムファイルだけでなくファイル記述子も消費します。ちょっとした考え。
Fdsは自分で処理できます。 JavaのexecはProcessオブジェクトを返します。プロセスがまだ実行中かどうかを断続的に確認します。プロセスが終了したら、STDERR、STDIN、およびSTDOUTストリームを閉じます。 )。これにより、リークが軽減されます。
この問題は、多くのファイルに同時にデータを書き込んでおり、オペレーティングシステムにオープンファイルの固定制限がある場合に発生します。 Linuxでは、開いているファイルの制限を増やすことができます。
https://www.tecmint.com/increase-set-open-file-limits-in-linux/