Подтвердить что ты не робот

IOException: слишком много открытых файлов

Я пытаюсь отлаживать утечку дескриптора файла в Java webapp, работающем в Jetty 7.0.1 на Linux.

Приложение было успешно запущено в течение месяца или около того, когда запросы начали сбой из-за слишком большого количества открытых файлов, и 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)

Сначала я думал, что проблема связана с кодом, запускающим внешнюю программу, но с использованием 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, через несколько дней их сотни.

Я знаю, что это немного неопределенно на данном этапе, но есть ли у вас какие-либо предложения о том, где искать дальше, или как получить более подробную информацию об этих дескрипторах файлов?

4b9b3361

Ответ 1

Ваша внешняя программа не ведет себя правильно. Посмотрите, почему это не делает.

Ответ 2

Проблема возникает из вашего приложения Java (или библиотеки, которую вы используете).

Сначала, вы должны прочитать все выходы (Google для StreamGobbler) и pronto!

Javadoc говорит:

Родительский процесс использует эти потоки для подачи ввода и получения вывода из подпроцесс. Потому что некоторые родные платформы обеспечивают ограниченный буфер размер для стандартного ввода и вывода потоки, неспособность быстро написать входной поток или чтение выходного потока подпроцесса может вызвать подпроцесс блокировать и даже тупиковый.

Во-вторых, waitFor() ваш процесс завершается. Затем вы должны закрыть поток ввода, вывода и ошибок.

Наконец destroy() ваш процесс.

Мои источники:

Ответ 4

Не знаю характер вашего приложения, но я видел, как эта ошибка проявлялась несколько раз из-за утечки пула соединений, поэтому стоит проверить. В Linux соединения сокетов потребляют файловые дескрипторы, а также файлы файловой системы. Просто мысль.

Ответ 5

Помимо поиска проблем с корневыми причинами, таких как утечки файлов и т.д., чтобы сделать законное увеличение предела "открытых файлов" и которые сохраняются при перезагрузке, рассмотрите возможность редактирования

/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.

Ответ 6

Вы можете обращаться с fds самостоятельно. Exec в java возвращает объект Process. Периодически проверяйте, продолжает ли процесс. Как только он завершит работу с потоками STDERR, STDIN и STDOUT (например, proc.getErrorStream.close()). Это уменьшит утечки.