it-roy-ru.com

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

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

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

25
Mirko N.

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

7
Thorbjørn Ravn Andersen

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

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

Javadoc говорит:

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

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

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

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

24
ofavre

Поскольку вы работаете в Linux, я подозреваю, что у вас заканчиваются файловые дескрипторы. Проверьте ulimit. Вот статья, которая описывает проблему: http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/

8
Greg Smith

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

/etc/security/limits.conf

добавив что-то вроде этого

jetty soft nofile 2048
jetty hard nofile 4096

где "jetty" - это имя пользователя в этом случае. Для получения дополнительной информации о limit.conf см. http://linux.die.net/man/5/limits.conf

выйдите, а затем снова войдите и запустите

ulimit -n

чтобы убедиться, что изменение произошло. Новые процессы этого пользователя теперь должны соответствовать этому изменению. Эта ссылка , кажется, описывает, как применить ограничение к уже запущенным процессам, но я не пробовал.

Ограничение по умолчанию 1024 может быть слишком низким для больших приложений Java.

5
Rami Jaamour

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

5
alasdairg

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

2
allenjsomb

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

https://www.tecmint.com/increase-set-open-file-limits-in-linux/

Как изменить ограничение количества открытых файлов в Linux?

0
Vpn_talent