После работы с другим клиентом Pivotal (GemFire) над аналогичной проблемой (также используя Spring Session и Pivotal GemFire (SSDG) для управления состоянием сеанса HTTP в высокопараллельном веб-приложении / среде), мы обнаружили,основные проблемы и, в конечном итоге, обнаруженные ошибки в Pivotal GemFire!
В двух словах, эти ошибки приводят к потерянным обновлениям из-за RaceУсловия , которые раздражены в высококонкурентной (многопользовательской) веб-среде, где несколько HTTP-запросов могут получить доступ и изменить один и тот же сеанс HTTP под нагрузкой.И чем больше параллелизм (пользователи) и чем больше нагрузка (количество HTTP-запросов к одному и тому же сеансу HTTP), тем более очевидной становится эта проблема.
На самом деле я написал несколько интеграционных тестов, иллюстрирующих этопроблема.
Сначала я написал тест интеграции нагрузки (MultiThreadedClientProxyRegionSessionIntegrationTests
).Этот класс порождает 180 потоков (пользователей), выполняющих 10 000 одновременных запросов к одному базовому Session
.Session
объект, хотя и не совсем тот же, смоделирован после представления GemFireSession
объекта SSDG.
Во-вторых, я написал еще один интеграционный тест (TwoThreadsClientProxyRegionSessionIntegrationTests
), который надежно и многократновоспроизводит проблему.
Оба этих тестовых класса были написаны исключительно с использованием GemFire API , тем самым иллюстрируя, что проблема связана с Pivotal GemFire, а не с SSDG.
Я написаланалогичный тест с использованием Spring Session Data GemFire как в моем примере , так и сейчас, , включенном в набор тестов SSDG (наряду со многими другими MultiThread /Интеграционные тесты на основе параллелизма ) сами по себе гарантируют, что Spring Session (для Pivotal GemFire) больше никогда не столкнется с этой проблемой, и если это произойдет, я узнаю об этом раньше, чем позже.
Короче говоря, 2 основных ошибки Pivotal GemFire:
Обходной путь выглядит следующим образом:
Во-первых, вы должны настроить клиентское приложение Spring Session, GemFire для кэширования следующим образом:
- Клиент
PROXY
Регион для управления состоянием Session
(по умолчанию) - Установить
copy-on-read
установить на true . И вы должны использовать GemFire DataSerialization, установив sessionSerializerBeanName
соответствующим образом:
@ SpringBootApplication @ClientCacheApplication (copyOnRead = верно, subscriptionEnabled = истина) @EnableGemFireHttpSession (clientRegionShortcut = ClientRegionShortcut.PROXY, sessionSerializerBeanName = GemFireHttpSessionConfiguration.SESSION_DATA_SERIALIZER_BEAN_NAME) класс MySpringBootSpringSessionDataGemFireApplication {...}
См здесь , например.
Вам также потребуется обновить до Spring Session для Pivotal GemFire 2.1.2.RELEASE
(будет выпущен в ближайшее время),так как я сделал несколько важных недавних улучшений, таких как:
- Проблема № 12 - Предотвращение SessionRepository.save (Session) для незапятнанных сессий.
- Проблема № 9 - добавлена поддержка конфигурации на стороне сервера для GemFire / Geode DataSerialization, когда SSDG не используется для настройки Spring Session на серверах.
- Проблема № 17. Рассмотрим поддержку настраиваемой проверки объекта домена приложения IsDirty.
Использование GemFire DataSerialization с Deltas не помешает, но значительноуменьшает вероятность потерянных обновлений и других состояний гонки, которые по своей природе наследуются в веб-среде, в частности, поскольку контейнер сервлетов (например, Tomcat) является многопоточным, обрабатывая каждый HTTP-запрос в отдельном потоке.
Несмотря на то, что SSDG прилагает огромные усилия для обеспечения того, чтобы представление сеанса HTTP (т. Е. GemFireSession
) было поточно-ориентированным, вы также должны убедиться, что любой объект, который вы помещаете в сеанс HTTP, также является поточно-ориентированным, поскольку он может и, скорее всего,будет доступен более чем одному потоку в веб-приложении с высокой степенью одновременности, особенно 1, где более одного HTTP-запроса могут одновременно обращаться к одному и тому же сеансу HTTP (по идентификатору сеанса).
В любом случае, пища дляподумал.
Когда указанная выше конфигурация используется, все работает как положено, а если нет, потерянные обновления могут и будут возникать из-за ошибок GemFire!
Фактически, мой нагрузочный тест показал, чтоиз 10000 обновлений сеанса, где добавлено ~ 9800 атрибутов сеанса, только ~ 1100 успешно завершены, что составляет колоссальную потерю данных ~ 89% !!!
Однако, когда применяется вышеуказанная конфигурация, все данныеучитывается правильно.
Надеюсь, это поможет!