Назад | Перейти на главную страницу

Утечка файлового дескриптора (конвейера) Linux в WildFly 12+

Я пытаюсь определить, правильное ли поведение, которое я наблюдаю, или если WildFly утекает дескрипторы дескрипторов файлов.

Во время стандартного тестирования производительности после обновления WildFly 11 до 14 мы столкнулись с проблемой, связанной со слишком большим количеством открытых файлов. После того, как мы углубимся в детали, похоже, что на самом деле количество каналов, открытых WildFly, увеличивается.

Чтобы воспроизвести проблему, я создал простое приложение JSF 2.2, содержащее большое изображение (100 МБ для упрощения тестирования). Я получаю изображение, используя стандартный URL-адрес ресурса JSF:

/contextroot/javax.faces.resource/css/images/big-image.png.xhtml

А также пробовали добавлять омнифасы и использовать несопоставленный URL-адрес обработчика ресурсов:

/contextroot/javax.faces.resource/css/images/big-image.png

Добавление Omnifaces не изменило поведение, которое я наблюдаю, и я включил его только потому, что мы сначала думали, что это могло быть способствующим фактором.

Я наблюдаю за поведением:
WildFly запускается, и jstack сообщает, что у него есть два совпадающих потока. default task-* что является значением по умолчанию для task-core-threads

Если я отправлю 5 одновременных запросов на мое большое изображение, 3 новых default task-* потоки создаются для обслуживания запросов. Также будут созданы 3 новых канала Linux.

Если я остановлю свои запросы и подожду 2 минуты (значение по умолчанию для task-keepalive) 3 нитки будут удалены. Трубы остаются открытыми.

Периодически - я полагаю, что каждые 4,5 минуты происходит какая-то очистка, и трубы, оставшиеся после шага выше, удаляются.

Однако ... Если один из исходных 2 рабочих потоков удален, например задача-1, задача-3 и задача-4 удаляются, оставляя задачу-2 и задачу-5, канал, связанный с задачей-1, никогда не очищается.

Со временем эти трубы складываются и, насколько я могу судить, никогда не удаляются. Это где-то утечка, и если да, то где? JSF? WildFly? Отлив?

Вещи, которые я пробовал:
WildFly 14, 17 и 18
С Omnifaces и без них (2.7 и 3.3)
Изменение минимального и максимального потоков одинаковыми - это предотвращает накопление дескрипторов, но я бы предпочел не идти по этому пути

Я тоже сталкиваюсь с подобной утечкой. Ручки «теряются» в тройках по две трубы и один селектор epoll. (@Gareth: не могли бы вы подтвердить это? Взгляните на / proc / $ PID / fd для каналов и анонимных inodes). Из этого кажется, что он порожден Java NIO Channels.

Я обнаружил, что ручки освобождаются (по крайней мере) при вызове полного сборщика мусора (@Gareth: можете ли вы это подтвердить)? Я использую хорошо настроенную Java8-JVM с включенным G1GC, и, что приятно, полный сбор мусора случается очень редко. Но, как отрицательное последствие, он тем временем израсходует тысячи этих троек FH.

Поскольку ручки могут быть освобождены, это не настоящая утечка, а результат Soft / Weak / Phantom-Reference.

И достигли назначенного лимита ОС (JVM с Wildfly работает внутри LX-контейнера) дважды на прошлой неделе. Поэтому в качестве первого обходного пути для производственной среды я написал сторожевой таймер, который вызывает FGC с помощью jcmd, если уровень обработчиков каналов поднимается до предела.

Это наблюдается на (сбалансированной) паре Wildfly-13, на которой запущено более 20 приложений. Кажется, это не связано с конкретным приложением, потому что это также происходит (на обоих Wildfly из пары), если я отключаю отдельные приложения от балансировки нагрузки (на одном из пары).

Он не «отображается» на других (парах) наших Wildflies, но есть другой набор приложений с другими вариантами использования. Больше циркуляции памяти и больше "давления" на кучу. Возможно, это вызовет современное высвобождение объектов, удерживающих файловые дескрипторы по-другому.

Взглянув на дамп кучи с помощью «Memory Analyzer Tool», я смог обнаружить сопоставимо большое и равное количество экземпляров sun.nio.ch.EPollArrayWrapper и sun.nio.ch.EPollSelectorImpl с входящими ссылками на org.xnio.nio.NioXnio$FinalizableSelectorHolder.