Утечка дескриптора файла (канала) 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

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

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

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

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

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

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

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

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

2
задан 16 October 2019 в 03:00
2 ответа

Я сталкиваюсь со своего рода этой утечкой, также. Дескрипторы "потеряны" в, утраивается двух каналов и одного epoll селектора. (@Gareth: можете Вы confim это? Смотрите на/proc/$PID/fd для каналов и анонимного inodes). От этого это, кажется, порождено Каналами NIO Java.

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

, поскольку дескрипторы публикуемы, это не реальная утечка, а эффект Soft/Weak/Phantom-Reference.

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

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

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

Путем взгляда на "куче" выводят с "Памятью Инструмент Анализатора", я смог обнаружить сопоставимое высокое и равное количество экземпляров sun.nio.ch.EPollArrayWrapper и sun.nio.ch.EPollSelectorImpl с входящими ссылками на org.xnio.nio.NioXnio$FinalizableSelectorHolder.

1
ответ дан 3 December 2019 в 12:28

Эта проблема начала возникать после переноса среды выполнения WildFly с Java с версии 8 на версию 11.

В версии Java 11 алгоритм GC по умолчанию был изменен на G1. В G1 объекты старого поколения собираются очень выборочно и только после достижения определенного порога заполнения кучи. Если у вас есть несколько объектов, которые переводятся в старое поколение и помогают достичь этого порога, возможно, org.xnio.nio.NioXnio$FinalizableSelectorHolder накапливается там очень долго, сохраняя дескрипторы открытых файлов. .

В моем случае переключение сборки мусора на использование одновременной маркировки и очистки решило проблему, хотя я совершенно уверен, что G1 можно настроить для более агрессивного сбора старого поколения. -XX:-G1UseAdaptiveIHOP и -XX:InitiatingHeapOccupancyPercent — это переключатели для игры. Другой подход может заключаться в уменьшении размера кучи старого поколения (–XX:NewRatio) или всей кучи.

0
ответ дан 6 July 2021 в 10:43