Вопрос или проблема
У меня есть приложение на Spring WebFlux с Java 17, Spring Boot 3.3.3 и Log4j2 со следующими настройками JVM.
-XX:+UseG1GC
-XX:+UnlockExperimentalVMOptions
-XX:G1HeapRegionSize=1
-XX:G1ReservePercent=10
-XX:+DisableExplicitGC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=45
-XX:G1NewSizePercent=25
-XX:G1MaxNewSizePercent=30
-XX:TargetSurvivorRatio=25
-Xms1250m -Xmx1250m
—add-reads=jdk.jfr=ALL-UNNAMED
Конфигурация CPU
Ограничения:
Cpu: 1500m
Память: 2800Mi
Запросы:
Cpu: 200m
Память: 1800Mi
Когда я провел нагрузочное тестирование с 20 TPS в течение 2 дней подряд. На старте теста использование кучи было на уровне 45%, затем в процессе теста в течение 3 дней среднее использование кучи постепенно увеличивалось, и в один момент достигло почти 80-85% на третий день, что вызвало крупную сборку мусора 3 раза.
Когда я сделал дамп кучи, я увидел, что у Log4j Logger почти 3078102 экземпляров, и они занимают почти 100 МБ, а 1 экземпляр Log4jLoggerFactory занимает 180 МБ.
Из ссылки на Logger, когда я открыл путь к ссылке GC, я увидел одну ссылку на класс приложения, который содержит несколько ссылок на экземпляры логгеров.
Указывает ли это на то, что конкретный класс приложения не освобождает экземпляры логгера?
В этом классе приложения я печатаю POJO в информационном режиме.
Кроме этих 2 классов все остальные классы приложения занимают очень немного памяти, не уверен, является ли это утечкой памяти, если да, то как выяснить, что является причиной утечки памяти.
Ответ или решение
Проблема с памятью в Spring Webflux при использовании Log4j2
Ваша ситуация, связанная с тем, что при нагрузочном тестировании ваше приложение на Spring Webflux с использованием Log4j2 достигает высокойUtilization кучи, указывает на возможную проблему с утечками памяти. Давайте разберем это более подробно.
Анализ проблемы
-
Высокое использование памяти:
- Вы отмечаете, что при проведении теста производительности среднее использование кучи увеличивается до 80-85%, что является значительным повышением. Это может свидетельствовать о том, что объекты в памяти не освобождаются должным образом.
-
Анализ свалок памяти:
- Вы сделали дамп памяти и выяснили, что у вас имеется более 3 миллионов экземпляров
Log4jLogger
, которые занимают около 100 МБ. Кроме того, один экземплярLog4jLoggerFactory
занимает около 180 МБ.
- Вы сделали дамп памяти и выяснили, что у вас имеется более 3 миллионов экземпляров
-
Ссылки на логгеры:
- Из анализа ссылок на объекты видно, что конкретный класс приложения удерживает ссылки на несколько экземпляров логгеров. Это может быть признаком того, что этот класс не освобождает ссылки на логгеры, что приводит к утечке памяти.
Возможные решения
-
Проверка реализации логирования:
- Просмотрите реализацию вашего класса, который использует логгеры, и проверьте, создаете ли вы новые экземпляры логгеров каждый раз, когда вызываете метод логирования. В Log4j2 принято использовать один экземпляр логгера на класс:
private static final Logger logger = LogManager.getLogger(YourClass.class);
- Просмотрите реализацию вашего класса, который использует логгеры, и проверьте, создаете ли вы новые экземпляры логгеров каждый раз, когда вызываете метод логирования. В Log4j2 принято использовать один экземпляр логгера на класс:
-
Предотвращение создания лишних логгеров:
- Убедитесь, что вы не создаете новые логгеры в каждом методе или в циклах, так как это может привести к большому количеству экземпляров. Логгеры должны быть статическими и финализированными для минимизации потребления памяти.
-
Использование конфигурации логирования:
- Проверьте настройки конфигурации Log4j2 и убедитесь, что они оптимальны. Например, использование сетевых или файл логирования может иметь свое влияние на память. Также ограничьте размер журналов и количество хранений, если это возможно, особенно на высоких нагрузках.
-
Оптимизация сообщений для логирования:
- Если вы логируете большие объекты (например, POJO), подумайте о том, чтобы логировать только ключевые атрибуты, а не весь объект. Это значительно сократит объем данных, которые обрабатываются и хранятся.
-
Проверка других источников утечек памяти:
- Убедитесь, что другие объекты и классы, которые могут удерживать ссылки на логгеры, также правильно освобождаются, особенно если они используют кэширование или статические поля.
Инструменты для анализа утечек памяти
Если вышеуказанные шаги не помогут, рассмотрите возможность использования инструментов для анализа утечек памяти:
- VisualVM или Eclipse Memory Analyzer (MAT) позволят вам более детально проанализировать дампы памяти и выявить объекты, которые используются более длительное время, чем ожидалось.
- Java Flight Recorder может помочь вам получить данные о производительности вашего приложения и получить дополнительное представление о проблемах с использованием памяти.
Заключение
Ваша проблема, судя по всем собранным доказательствам, скорее всего, связана с неправильным управлением экземплярами логгеров. Следуйте приведенным выше рекомендациям, чтобы попытаться устранить утечки памяти и улучшить общую производительность вашего приложения на базе Spring Webflux с использованием Log4j2.