«Слишком много открытых файлов» в приложении Grails - как правильно закрыть открытые файлы и потоки? - PullRequest
5 голосов
/ 05 января 2012

Я занимаюсь разработкой довольно сложного веб-приложения, которое вызывает несколько выполняемых извне процессов, фоновый процесс grails и читает / записывает из / в несколько файлов - все в одном контроллере. Все было хорошо, пока я не проверил это со многими запросами в непосредственной близости. Когда я делаю это, я получаю следующее сообщение об ошибке Java в моем лог-файле tomcat catalina:

WARNING: Exception executing accept
java.net.SocketException: Too many open files
    at java.net.PlainSocketImpl.socketAccept(Native Method)
    at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
    at java.net.ServerSocket.implAccept(ServerSocket.java:462)
    at java.net.ServerSocket.accept(ServerSocket.java:430)
    at org.apache.jk.common.ChannelSocket.accept(ChannelSocket.java:312)
    at org.apache.jk.common.ChannelSocket.acceptConnections(ChannelSocket.java:666)
    at org.apache.jk.common.ChannelSocket$SocketAcceptor.runIt(ChannelSocket.java:877)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
    at java.lang.Thread.run(Thread.java:662)

Сначала, после некоторого счастливого поиска в Google и чтения, я подозревал, что это может быть «системная проблема», то есть, что мне нужно поднять лимит для открытых файлов для пользователя, который запускает tomcat - но это не так.

Затем я начал читать множество советов по Java, а не по Grails & Groovy, потому что, если вы решите эту проблему с помощью Grails, вы не найдете так много. Теперь я подозреваю, что моя проблема вызвана «слишком большим количеством открытых потоков» (или чем-то в этом роде), а не слишком большим количеством действительно открытых файлов (так как количество открытых файлов действительно НЕ ТАКОЕ большое).

У меня много операций следующих четырех типов в одном замыкании:

1) Открытие файлов и запись в них:

def someFile = new File("/some/file.txt")
someFile << "Some content\n"

2) Выполнение команд:

def cmd = "bash some-cmd".execute()
cmd.waitFor()

3) Чтение содержимого из файлов:

def fileContent = new File("/some/file.txt").text

4) Чтение контента из файлов в сети:

def URL url = new URL("http://www.some.link");
def URLConnection uc = url.openConnection()
def BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream()))
...
br.close()

Как видите, единственное, что я явно закрываю, это BufferedReader с InputStream, я полагаю, что br.close () закрывает их оба.

Должен ли я закрыть какие-либо другие открытые соединения, или лучше: я могу это сделать? Какова будет команда, чтобы сделать это? Или вы думаете, что моя проблема действительно не вызвана "забытым, открытым потоком"?

Мой вопрос в основном возникает из ответов на Почему я получаю ошибки "Too many open files"? и IOException: Слишком много открытых файлов .

Я использую Grails 1.1.1 (я ЗНАЮ, что он устарел, но у меня были серьезные проблемы с переносом приложения на текущую версию, и я разочаровался в нем после многих часов работы), groovy 1.8.0, tomcat 6.0. 28, apache 2.2.16 в Ubuntu 10.10.

Ответ на решение моей проблемы «Слишком много открытых файлов» очень связан с ответом Стивена С. Похоже, что первой причиной моей ошибки был действительно закрытый поток BufferedReader. Я в основном перенес его предложение с Java-кодом прямо в Grails:

def URL url = new URL("http://www.some.link");
def URLConnection uc = url.openConnection()
def BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream()))
try{
    ...
}finally{
    br.close()
}

-> Это определенно решило проблему с «Слишком много открытых файлов», и теперь я даже могу увидеть, каков был реальный источник проблемы.

Ответы [ 3 ]

4 голосов
/ 05 января 2012

Как видите, единственное, что я явно закрываю, это BufferedReader с InputStream, я полагаю, что br.close () закрывает их оба.

Да, но только если оно выполнено.

Я не программист на Groovy / Grails, но в Java есть распространенная ошибка, которую допускают люди, что может привести к утечке дескриптора файла. Например,

InputStream is = new FileInputStream(someFile);

// do some work
...

is.close();

Проблема в том, что операторы, обозначенные многоточием (...), могут вызвать исключение. Если они это делают, вызов is.close() не происходит, и дескриптор файла просачивается. Решение (на Java) - написать код, подобный следующему:

InputStream is = new FileInputStream(someFile);
try {
   // do some work
   ...
} finally {
   is.close();
}

или (в Java 7) как:

try (InputStream is = new FileInputStream(someFile)) {
   // do some work
   ...
}
0 голосов
/ 31 мая 2013

Применяются ответы как @Sunil Kumar Sahoo, так и @Stephen C.

Обычно вы выполняете следующие шаги в следующем порядке:

  • Убедитесь, что у вас есть попытка / улов/ finally блокируется для закрытия ресурсов ввода-вывода
  • Проверьте настройки ulimit при работе с блоками UNIX / Linux.Это действительно зависит от потребностей приложения.
0 голосов
/ 05 января 2012

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

Если вы используете Linux, используйте ulimit, чтобы установить максимальный лимит файлов для системы. В linux ограничение по умолчанию для файлов составляет 1024

ulimit -n 2048 // to set the file limit to 2048
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...