Страницы

Поиск по вопросам

среда, 10 октября 2018 г.

Использование механизма сессий для хранения временных данных

В разрабатываемом приложении осуществляется тестирование пользователей. Естественно во время теста возникла необходимость сохранять промежуточные итоги: Количество ошибок, количество правильных ответов и пр. В начале планировалось проводить тест почти полностью на клиенте, но потом возникли сложности с тем чтобы защититься от подделки данных и решено было перенести все на сервер. Теперь возник вопрос: Разумно ли и безопасно хранить текущие данные в сессии или лучше добавлять их в БД?


Ответ

Безопасно. Сессия полностью хранится на серверной стороне. Но вот разумно ли - зависит от мнения. Мое мнение:
НИ В КОЕМ СЛУЧАЕ НЕ ИСПОЛЬЗУЙТЕ СТАНДАРТНЫЙ МЕХАНИЗМ СЕССИЙ В ASP.NET
...и опирающийся на него же механизм TempData. Практически ни к коем случае, кроме редких исключений, описанных в конце ответа.
Несмотря на всю простоту использования, у механизма сессий есть огромное количество потенциальных проблем.
Проблемы из-за самого наличия сессионной куки
Запросы с общей сессионной кукой всегда выполняются последовательно. ASP.NET тупо не может выполнить два запроса из одной сессии одновременно. Он ставит их в очередь и вызывает по одному. Это дико бьет по производительности. Если пользователь запустил что-то долгое (репорт на минуту) на сайте в одном табе - то в другом табе сайт у него тупо будет висеть. Это написано мелким шрифтом в MSDN на странице, посвященной сессиям, но кто ж читает MSDN.
Это частично решается явным отключением сессии для всех страниц и всех контроллеров по умолчанию, и выборочным включением ее для отдельных действий, в случае необходимости.
Проблемы со стандартным способом хранения - InProc:
Стандартный механизм хранения сессий ненадежен. Он будет терять данные при ресайкле приложения - при неактивности, при большой нагрузке, при заливке новой версии. Стандартный механизм хранения сессий не масштабируется. Он просто не работает в случае двух серверов. Или одного сервера и двух рабочих процессов. Или одного сервера, одного рабочего процесса при включенном Overlapping Recycling.
Проблемы с хранением сессии в SQL Server:
В зависимости от объема хранимых данных - это может быть медленно. SQL Server не приспособлен к хранению больших объемов данных прямо в таблице. Он делает это меееедлееенно. Проблема "в один момент времени - один запрос" при этом выходит на новый уровень. Теперь каждый запрос, использующий сессию, ставит на нее блокировку. Вызовом SQL. А потом снимает ее. Вызовом SQL. Что дает вам два запроса к базе на ровном месте, даже если контроллер не лезет в сессию. В зависимости от провайдера, можно напороться еще и на проблему в очисткой сессий, например, рекомендованные (с) System.Web.Providers (r), при обработке каждого запроса лезут в базу еще и для того, чтобы почистить старые сессии. Каждого запроса, Карл!
Что использовать вместо сессий
В живом - открытом в интернет, или просто доступном большому количеству пользователей приложении альтернатив в смысле "правильных замен сессии" нет.
Сама по себе необходимость организовать что-то вроде сессии - это прямой и однозначный признак просчета в архитектуре. Использование сессий или любого их подобия практически означает невозможность распределенного деплоя. Убирает возможность эффективно использовать кэш. Сессии - это всегда bottleneck. Если они нужны - значит вы делаете что-то неправильно.
Например, в случае с приложением для тестирования стоит хранить на клиенте данные ответы. Это не исключает хранения промежуточных итогов, но окончательный итог надо подсчитывать на сервере, и только с использованием самих ответов, а не промежуточных итогов. Промежуточные итоги можно использовать для валидации - если вдруг что-то разошлось - значит клиент пытался читерить.
С другой стороны
если у вас intranet-приложение, которым пользуются, например, студенты, при прохождении теста, то одного сервера с одним рабочим процессом и настроенным хранением сессии в ASP.NET State Server вам хватит заглаза. От вас потребуется только поставить стандартный сервер через вызовом aspnet_state.exe, прописать режим StateServer в конфиге и отметить все хранимые объекты как сериализуемые.
Это в разы проще, чем ручная организация хранения сложных временных объектов в базе.
Только режим хранения InProc не используйте - он не предназначен для использования в хоть насколько-то рабочем окружении.

Комментариев нет:

Отправить комментарий