Благодаря этому мы можем масштабировать наше приложение, добавлять новые узлы, удалять узлы, не заботясь о репликации сеансов, а также о потребляемой памяти кучи Java.
Недавно я работал над REST-приложением с высокой нагрузкой. На самом деле мы не ожидали, что там будет большой трафик, но на удивление у нас было намного больше, к чему мы были подготовлены (это так называемая «счастливая проблема»). Приложение основано на Spring Framework и защищено с помощью Spring Security, развернутой на Apache Tomcat 7 . Все ресурсы полностью не сохраняют состояние — HttpSession не затрагивается ни одним фрагментом моего кода. К сожалению, используемое пространство кучи Java постоянно увеличивалось, пока:
1
|
java.lang.OutOfMemoryError: Java heap space |
был брошен. Для анализа дампа кучи Java и использования кучи во время выполнения я использовал VisualVM .
Анализ дампа кучи показал, что большая часть памяти была использована ConcurrentHashMaps, используемой Tomcat для хранения сеансов. Эти объекты сессий были почти пустыми, но их было так много, что они занимали ~ 50% зарезервированного пространства кучи Java.
Добавьте параметр в сценарий запуска Tomcat: -XX:+HeapDumpOnOutOfMemoryError
чтобы получить дамп кучи Java для java.lang.OutOfMemoryError: Java heap space
Первым делом я ограничил время ожидания сеанса с 30 минут до 1 минуты (минимально возможный вариант) в web.xml
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<? xml version = '1.0' encoding = 'UTF-8' ?> xsi:schemaLocation='http://java.sun.com/xml/ns/javaee version = '3.0' > <!-- ... --> < session-config > < session-timeout >1</ session-timeout > </ session-config > </ web-app > |
Это решило проблему — куча была очищена GC с лучшими результатами, и OutOfMemoryError больше не генерировался. Но что важнее, откуда взялись эти сессии? Ответ: Spring Security.
По умолчанию Spring Security создает сеансы при необходимости — это означает, что если пользователь успешно прошел аутентификацию, то сеанс создается. В моем случае это meaan — всегда. Чтобы запретить Spring Security create-session='never'
необходимо добавить create-session='never'
в http
:
1
2
3
|
< http create-session = 'never' > <!-- ... --> </ http > |
Вы можете подумать — пустые объекты сессии не должны быть проблемой. Я могу вам сказать, что для приложения, обрабатывающего несколько сотен запросов в секунду, это действительно меняет ситуацию. Особенно, когда он не работает в облаке или имеет мало ГБ или оперативной памяти, выделенной для кучи Java. Вот как выглядит использование кучи Java после этих изменений:
Справка: Решение проблемы с сеансами REST + Spring Security от нашего партнера по JCG Мачея Уоковяка в блоге « Путь к разработке программного обеспечения» .