Этот вопрос очень похож на ваш последний вопрос .И вы должны прочитать мой ответ на этот вопрос, прежде чем читать мой ответ / комментарии здесь.
Предыдущий ответ (и понимание), размещенный анонимным пользователем, является довольно точным.
Каждый раз, когда у вас есть высококонкурентное (веб) приложение / среда, где поступает много разных одновременных HTTP-запросов, обращающихся к одному и тому же HTTP-сеансу, всегда есть вероятность потерянных обновлений вызвано условиями гонки между конкурирующими параллельными HTTP-запросами.Это связано с самой природой контейнера сервлетов (например, Apache Tomcat или Eclipse Jetty), поскольку каждый HTTP-запрос обрабатывается отдельным потоком и внутри него.
Не только объект сеанса HTTP, предоставляемыйконтейнер сервлетов должен быть поточно-ориентированным, но также и все объекты домена приложения, которые ваше веб-приложение помещает в сеанс HTTP.Итак, помните об этом.
Кроме того, большинство реализаций сеансов HTTP, таких как Apache Tomcat или даже реализация сеансов Spring Session , поддерживаются различными поставщиками управления сеансами (например, Spring).Данные сеанса Redis или Spring Session Data GemFire ) широко используют «дельты» для отправки только изменений (или различий) в состояние сеанса, сводя к минимуму вероятность потери обновляет из-за условий гонки .
Например, если сеанс HTTP в настоящее время имеет ключ / значение атрибута 1/A
и HTTP-запрос 1 (обработанный потоком 1) считываетсеанс HTTP (только с 1/A
) и добавляет атрибут 2/B
, в то время как другой параллельный запрос HTTP 2 (обработанный потоком 2) считывает тот же сеанс HTTP по идентификатору сеанса (видя то же самое начальное состояние сеанса с 1/A
), и теперь он хочет добавить 3/C
, тогда, как разработчики веб-приложений, мы ожидаем, что конечный результат и состояние сеанса HTTP будут, после запроса 1& 2 в темах 1 и 2 завершены, включая атрибуты: [1/A, 2/B, 3/C]
.
Однако, если 2 (или даже больше) конкурирующих HTTP-запроса модифицируют, скажем, атрибут HTTP sessoin 1/A
и HTTP-запрос / поток1 хочет установить для атрибута 1/B
, а конкурирующий HTTP-запрос / Поток 2 хочет установить для того же атрибута 1/C
, тогда кто выигрывает?
Ну, получается, последние 1 побед, или, скорее,последний поток, записывающий состояние сеанса HTTP, выигрывает, и результатом может быть 1/B
или 1/C
, который является неопределенным и зависит от капризов планирования, задержки в сети, нагрузки и т. д. и т. д. Фактически этоПочти невозможно предположить, что произойдет, гораздо реже случается.
В то время как наш анонимный пользователь предоставил некоторый контекст, скажем, для пользователя, использующего несколько устройств (веб-браузер и, возможно, мобильное устройство ... смартфон)или планшет) одновременно, воспроизведение такого рода ошибки с одним пользователем, даже несколько пользователей не было бы невозможно, но очень маловероятно.
Но если мы подумаем об этом в производственном контексте, где у вас может быть, скажем, несколько сотен экземпляров веб-приложений, распределенных по нескольким физическим машинам, или виртуальным машинам, или контейнерам, и т. Д., Балансировка нагрузки выполняется каким-либо балансировщиком / устройством сетевой нагрузки, изатем добавим тот факт, что многие веб-приложения сегодня являются «одностраничными приложениями», очень сложными, не тупыми (уже не тонкими), но толстыми клиентами с вызовами JavaScript и AJAX, и мы начинаем понимать, что этот сценарий гораздо более вероятен, особеннов сильно загруженном веб-приложении;думаю, Amazon или Facebook.Не только много одновременных пользователей, но и много одновременных запросов от одного пользователя с учетом всех динамических асинхронных вызовов, которые может выполнять веб-приложение.
Тем не менее, как указал наш анонимный пользователь, это не оправдывает веб-приложение.разработчик ответственно проектирует и кодирует наше веб-приложение.
В целом, я бы сказал, что HTTP-сеанс должен использоваться только для отслеживания очень минимальной (то есть по количеству) и необходимой информации для поддержания хорошего пользовательского опыта и сохранения надлежащего взаимодействия между пользователем и приложением при переходе пользователя черезразличные части или фазы веб-приложения, такие как отслеживание предпочтений или элементов (в корзине).Как правило, сеанс HTTP не должен использоваться для хранения «транзакционных» данных.Должно быть так, чтобы попасть в беду.Сеанс HTTP должен быть в первую очередь структурой данных с интенсивным чтением (а не с интенсивной записью), особенно потому, что сеанс HTTP может и, скорее всего, будет доступен из нескольких потоков.
Конечно, разные хранилища данных (например,Redis и даже GemFire) предоставляют механизмы блокировки.GemFire даже предоставляет транзакции на уровне кэша, что является очень тяжелым и не подлежащим обсуждению, неуместным при обработке веб-взаимодействий, управляемых объектом сеанса HTTP и с ним (не путать с транзакциями).Даже блокировка может привести к серьезному конфликту и задержке приложения.
В любом случае, все это означает, что вам очень нужно осознавать взаимодействия и шаблоны доступа к данным, иначе вы окажетесь вгорячая вода, так что будьте осторожны, всегда!
Пища для размышлений!