Я занимаюсь разработкой довольно сложного веб-приложения, которое вызывает несколько выполняемых извне процессов, фоновый процесс 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()
}
-> Это определенно решило проблему с «Слишком много открытых файлов», и теперь я даже могу увидеть, каков был реальный источник проблемы.