Таким образом, мы используем Spring websocket STOMP + RabbitMQ на внутренней стороне, и у нас возникают проблемы с дескрипторами открытых файлов.Через некоторое время мы достигли лимита на сервере, и сервер не принимает никаких соединений, включая веб-сокеты и конечные точки API.
2018-09-14 18:04:13.605 INFO 1288 --- [MessageBroker-1]
o.s.w.s.c.WebSocketMessageBrokerStats : WebSocketSession[2 current WS(2)-
HttpStream(0)-HttpPoll(0), 1159 total, 0 closed abnormally (0 connect
failure, 0 send limit, 63 transport error)], stompSubProtocol[processed
CONNECT(1014)-CONNECTED(1004)-DISCONNECT(0)], stompBrokerRelay[9 sessions,
127.0.0.1:61613 (available), processed CONNECT(1015)-CONNECTED(1005)-
DISCONNECT(1011)], inboundChannel[pool size = 2, active threads = 2, queued
tasks = 2, completed tasks = 12287], outboundChannelpool size = 0, active
threads = 0, queued tasks = 0, completed tasks = 4225], sockJsScheduler[pool
size = 1, active threads = 1, queued tasks = 3, completed tasks = 683]
И мы получаем следующие исключения:
2018-09-14 18:04:13.761 ERROR 1288 --- [http-nio-127.0.0.1-8443-Acceptor-0]
org.apache.tomcat.util.net.NioEndpoint : Socket accept failed
java.io.IOException: Too many open files
at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422)
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250)
at org.apache.tomcat.util.net.NioEndpoint$Acceptor.run(NioEndpoint.java:455)
at java.lang.Thread.run(Thread.java:748)
Предел дескриптора файла по умолчанию для linux - 1024, и даже если мы увеличим его до 65000, он в какой-то момент достигнет предела, несмотря ни на что.
Мы хотим решить эту проблему иззадняя сторона и желательно к весне без каких-либо обходных путей.Есть идеи?
ОБНОВЛЕНИЕ
RabbitMQ и приложение находятся на разных серверах.На самом деле RabbitMQ работает на Compose.Мы можем воспроизвести эту проблему, не отправляя DISCONNECT сообщений от клиента.
ОБНОВЛЕНИЕ 2
Сегодня я понял, что все файловые дескрипторы и JavaНити всегда остаются там, независимо от того, что происходит.Я реализовал обходной путь, который включает отправку DISCONNECT сообщений из Spring и закрытие объектов WebSocketSession
без изменений.Я реализовал их, проверив приведенные ниже ссылки:
И, как примечание стороны, серверная сторона отправляет такие сообщения: simpMessagingTemplate.convertAndSend("/queue/" + sessionId, payload)
.Таким образом, мы гарантируем, что каждый клиент получит соответствующее сообщение от соответствующей sessionId.
Это какая-то ошибка?Почему дескрипторы файлов не закрываются?Никто раньше не сталкивался с этой проблемой?
ОБНОВЛЕНИЕ 3
Каждый раз, когда сокет закрывается, я вижу следующее исключение.Неважно, как он закрывается, либо с помощью DISCONNECT сообщения от клиента или webSocketSession.close()
кода с сервера.
[reactor-tcp-io-66] o.s.m.s.s.StompBrokerRelayMessageHandler : TCP connection failure in session 45r7i9u3: Transport failure: epoll_ctl(..) failed: No such file or directory
io.netty.channel.unix.Errors$NativeIoException: epoll_ctl(..) failed: No such file or directory
at io.netty.channel.unix.Errors.newIOException(Errors.java:122)
at io.netty.channel.epoll.Native.epollCtlMod(Native.java:134)
at io.netty.channel.epoll.EpollEventLoop.modify(EpollEventLoop.java:186)
at io.netty.channel.epoll.AbstractEpollChannel.modifyEvents(AbstractEpollChannel.java:272)
at io.netty.channel.epoll.AbstractEpollChannel.clearFlag(AbstractEpollChannel.java:125)
at io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe.clearEpollRdHup(AbstractEpollChannel.java:450)
at io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe.epollRdHupReady(AbstractEpollChannel.java:442)
at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:417)
at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:310)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884)
at java.lang.Thread.run(Thread.java:748)
Поэтому я изменил уровень журналов на TRACE
и я вижу, что веб-розетки действительно закрыты, но сразу же создаются эти исключения.Поэтому на данный момент я действительно с подозрением отношусь к этому исключениюКоличество зависших java-потоков всегда идет рука об руку с количеством веб-сокетов, т.е. создание 400 веб-сокетов всегда приводит к ~ 400 зависшим потокам в основном процессе.И ресурсы памяти никогда не высвобождаются.
Поиск в Google этого исключения заканчивается только следующими 4 результатами: (Остальное - другие исключения)
Обновление библиотеки netty
до последней версии (4.1.29.Final) didnтоже не работает, поэтому я изменил метки вопроса соответственно.Я также рассматриваю возможность создания проблемы против netty
.Я много чего перепробовал и несколько раз экспериментировал на уровне приложений, но, похоже, ничего не получалось.Я открыт для любых идей на данный момент.