Статьи

Проблема REST + Spring Security

ОТДЫХ , сессии .. подожди. В приложении REST нет сессий, верно? Ну, это правда. Если мы можем избежать сессий, мы должны это сделать. ОТДЫХ без гражданства . Основное беспокойство о безгражданстве — аутентификация. В обычных веб-приложениях нас использовали для хранения пользовательских данных в сеансе после аутентификации. Как решить это, если мы не хотим использовать сессии? Мы должны подтвердить подлинность каждого запроса .

Благодаря этому мы можем масштабировать наше приложение, добавлять новые узлы, удалять узлы, не заботясь о репликации сеансов, а также о потребляемой памяти кучи 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'?>
         xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
         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 Мачея Уоковяка в блоге « Путь к разработке программного обеспечения» .