Tomcat постепенно исчерпывает память при развертывании приложений WebSocket
У меня есть Tomcat 8.5.9, работающий в окне AWS с 10 различными приложениями WebSocket, которые каждый из них действует в качестве брокера сообщений. Коннектор https использует Http11NioProtocol. Единственным параметром, который я установил, является maxThreads = 200 вместе с информацией сертификата.
Объем запросов не очень высок. Он работает с утра понедельника, и вот что говорит статус менеджера:
Максимальные потоки: 200
Количество текущих потоков: 38
Текущий поток занят: 0
Держите живые сокеты: 1
Максимальное время обработки: 234 мс
Время обработки: 17.254 s
Количество запросов: 33351
Количество ошибок: 325
Полученные байты: 0.00 MB
Байты отправлены: 34.07 MB
Через несколько дней я заметил, что использование памяти продолжает расти. Я должен перезапустить службы Tomcat каждые две недели или около того, чтобы предотвратить получение исключения OutOfMemoryException.
Я использую кучи кучи и анализирую с помощью Mcl Eclipse, который всегда указывает на класс WsFrameServer как на подозрение на проблему. Самый последний дамп отображает следующее:
5,146 экземпляров "org.apache.tomcat.websocket.server.WsFrameServer",
загруженные "java.net.URLClassLoader @0x6c0047c28" занимают 1,383,143,200
(73,13%). Эти экземпляры ссылаются на один экземпляр "Java.util.concurrent.ConcurrentHashMap $Node []"
В Dominator Tree в настоящее время имеется 106 000 записей, большинство из которых - класс WsFrameServer.
Я делаю что-то неправильно или это "нормально"? Существуют ли какие-либо конкретные настройки на Tomcat или на Connector, которые я должен настроить, чтобы это не происходило?
Спасибо заранее.
EDIT: я не уверен, что это полезно, но вот как выглядит монитор VisualVM:
![VisualVM Monitor]()
Ответы
Ответ 1
Трудно быть уверенным без каких-либо подробностей, но это, вероятно, связано с сохранением сеанса.
Я думаю, что происходит, что WsFrameServer
, который расширяет WsFrameBase
добавляется в сеанс.
Если у вас неограниченная политика хранения сеансов, в конечном итоге у вас не хватит памяти.
Попробуйте установить не-0 sessionTimeout
Ответ 2
Код отсутствует в вашем вопросе. (особенно, как вы управляете подключением к сети)
Вы использовали tomcat в асинхронном режиме со списком подключения где-нибудь?
Вы не забудете привязать событие close AND к коду, который удаляет неисправное соединение из списка?
Ответ 3
Как мы все знаем, Java GC ленив. Его память будет продолжать расти, пока у нее не будет больше памяти, тогда GC будет запущен для сбора мусора.
Из скриншота вашего VisualVM мы можем видеть, что использование памяти относительно нормальное: больше памяти используется по мере того, как время идет, использование памяти падает после GC.
Итак, я задаюсь вопросом, действительно ли ваше приложение будет сбой, потому что OOM. Вы можете попробовать его в тестовой среде и получить сэмп OOM JVM для анализа, что более полезно.
Кстати, я предлагаю VisualVM над MAT, потому что MAT будет включать некоторые unreachable объекты как GC root. Это сделает анализ памяти очень неэффективным и даст другой результат в качестве других инструментов, которые я встретил в одном из наших проектов.