2010-01-11 4 views
22

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

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

Листинг открытых файлов на сервер можно увидеть большое количество FIFOs:

# 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 FIFOs, через несколько дней есть сотни из них.

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

+0

Давайте посмотрим код –

+0

Добавлен код запуска внешней программы. –

+0

В качестве дополнительного источника informaiton netstat -anp --tcp | grep --color может быть – zaletniy

ответ

7

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

+0

Итак, вы говорите, что это внешняя программа, которая теряет дескрипторы файлов? Но почему прекратить Jetty прояснить все FIFO тогда? –

+0

В некоторых случаях это действительно может быть ненормально, и я не могу этого избежать: это зависит от ввода пользователем. Но это может быть проблемой. –

+0

Вот проблема Хадсона: https://hudson.dev.java.net/issues/show_bug.cgi?id=715 –

8

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

+6

Это может привести к двум месяцам работы! (В лучшем случае это бандажная помощь.) –

+1

Вы повторили повторение симптома, но не настоящее лекарство. –

+0

На самом деле я действительно повысил лимит в '/ etc/security/limits.conf' уже по другим причинам. –

5

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

2

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

22

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

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

Javadoc говорит:

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

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

И, наконец,destroy() Ваш процесс.

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

+1

Это правильный ответ, который фактически содержит полезную информацию. –

+2

Вам не нужно уничтожать процесс, если 'waitFor()' преуспел. Процесс уже вышел. – EJP

4

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

/etc/security/limits.conf 

, добавляя что-то вроде этого

jetty soft nofile 2048 
jetty hard nofile 4096 

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

журнал выключен, а затем снова войти в систему и запустить

ulimit -n 

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

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