Вопрос

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

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

Javadoc говорит:

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

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

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

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

Поскольку вы работаете в Linux, я подозреваю, что у вас заканчиваются файловые дескрипторы.Посмотри на 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

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

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

ulimit -n

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top