Я только что обнаружил, что каждый запрос в веб-приложении ASP.Net получает блокировку сеанса в начале запроса, а затем освобождает его в конце запроса!
В случае, если последствия этого будут потеряны для вас, как это было сначала для меня, это в основном означает следующее:
Каждый раз, когда загрузка веб-страницы ASP.Net занимает много времени (возможно, из-за медленного вызова базы данных или чего-то еще), и пользователь решает, что он хочет перейти на другую страницу, потому что он устал ждать, ОНИ НЕ МОГУТ! Блокировка сеанса ASP.Net заставляет новый запрос страницы ждать, пока исходный запрос завершит свою мучительно медленную загрузку. Arrrgh.
Каждый раз, когда UpdatePanel загружается медленно, и пользователь решает перейти на другую страницу, прежде чем UpdatePanel закончит обновление ... ОНИ НЕ МОГУТ! Блокировка сеанса ASP.net заставляет новый запрос страницы ждать, пока исходный запрос завершит свою мучительно медленную загрузку. Двойной Arrrgh!
Так какие варианты? До сих пор я придумал:
- Реализуйте пользовательский SessionStateDataStore, который поддерживает ASP.Net. Я не нашел слишком много там, чтобы скопировать, и это кажется довольно рискованным и легко испортить.
- Отслеживайте все выполняющиеся запросы, и если запрос поступает от того же пользователя, отмените исходный запрос. Кажется, что-то вроде экстрима, но это сработает (я думаю).
- Не используйте сессию! Когда мне нужно какое-то состояние для пользователя, я мог бы вместо этого просто использовать Cache и ключевые элементы для аутентифицированного имени пользователя, или что-то подобное. Опять кажется экстремальным.
Я действительно не могу поверить, что команда Microsoft ASP.Net оставила бы такое огромное узкое место в производительности в версии 4.0! Я что-то упускаю из виду? Насколько сложно было бы использовать коллекцию ThreadSafe для сессии?
источник
Ответы:
Если ваша страница не изменяет какие-либо переменные сеанса, вы можете отказаться от большей части этой блокировки.
Если ваша страница не читает никаких переменных сеанса, вы можете полностью отказаться от этой блокировки для этой страницы.
Если ни одна из ваших страниц не использует переменные сеанса, просто отключите состояние сеанса в файле web.config.
Мне интересно, что, по вашему мнению, «коллекция ThreadSafe» могла бы сделать поточно-ориентированной, если она не использует блокировки?
Редактировать: я, вероятно, должен объяснить, что я имею в виду, «отказаться от большей части этой блокировки». Любое количество страниц только для чтения или без сеанса может обрабатываться для данного сеанса одновременно, не блокируя друг друга. Однако страница чтения-записи-сеанса не может начинать обработку до тех пор, пока не будут выполнены все запросы только для чтения, и во время ее работы она должна иметь монопольный доступ к сеансу этого пользователя для обеспечения согласованности. Блокировка отдельных значений не будет работать, потому что, если одна страница изменит набор связанных значений в группе? Как бы вы обеспечили, чтобы другие страницы, работающие одновременно, получали согласованное представление о переменных сеанса пользователя?
Я бы посоветовал вам попытаться свести к минимуму изменение переменных сеанса после их установки, если это возможно. Это позволит вам сделать большинство ваших страниц доступными только для чтения, что увеличит вероятность того, что несколько одновременных запросов от одного пользователя не будут блокировать друг друга.
источник
<pages enableSessionState="ReadOnly" />
в web.config и использует @Page, чтобы разрешить запись только на определенных страницах.Хорошо, такой большой реквизит Джоэлю Мюллеру за весь его вклад. Мое окончательное решение состояло в том, чтобы использовать Custom SessionStateModule, подробно описанный в конце этой статьи MSDN:
http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstateutility.aspx
Это было:
Это имело ОГРОМНОЕ отличие от ощущения «привязанности» к нашему приложению. Я до сих пор не могу поверить, что пользовательская реализация ASP.Net Session блокирует сеанс для всего запроса. Это добавляет огромное количество медлительности на веб-сайты. Судя по количеству онлайн-исследований, которые мне пришлось провести (и разговорам с несколькими действительно опытными разработчиками ASP.Net), многие люди сталкивались с этой проблемой, но очень мало людей когда-либо понимали причину проблемы. Может быть, я напишу письмо Скотту Гу ...
Я надеюсь, что это поможет нескольким людям там!
источник
ReaderWriterLock
он устарел в пользуReaderWriterLockSlim
- вы должны использовать его вместо этого. Во-вторых,lock (typeof(...))
также устарел - вместо этого следует блокировать частный экземпляр статического объекта. В-третьих, фраза «Это приложение не запрещает одновременным веб-запросам использовать один и тот же идентификатор сеанса» является предупреждением, а не функцией.SessionStateItemCollection
в примере кода классом, ориентированным на многопотоковое исполнение (возможно, на основеConcurrentDictionary
), если вы хотите избежать труднопроизводимых ошибок при загрузке.ISessionStateItemCollection
требует, чтобыKeys
свойствоSystem.Collections.Specialized.NameObjectCollectionBase.KeysCollection
имело тип - у которого нет открытых конструкторов. Ну и дела, спасибо, ребята. Это очень удобно.Я начал использовать AngiesList.Redis.RedisSessionStateModule , который, помимо использования (очень быстрого) сервера Redis для хранения (я использую порт windows - хотя есть и порт MSOpenTech ), абсолютно не блокирует сеанс ,
На мой взгляд, если ваше приложение структурировано разумно, это не проблема. Если вам действительно нужны заблокированные, непротиворечивые данные как часть сеанса, вы должны специально реализовать проверку блокировки / параллелизма самостоятельно.
По моему мнению, решение MS о том, что каждый сеанс ASP.NET должен быть заблокирован по умолчанию только из-за плохого дизайна приложения, является плохим решением Тем более, что большинство разработчиков, похоже, не понимали / даже не понимают, что сеансы были заблокированы, не говоря уже о том, что приложения, очевидно, должны быть структурированы, чтобы вы могли как можно больше выполнять состояние сеанса только для чтения (отказаться, где это возможно) ,
источник
Я подготовил библиотеку на основе ссылок, размещенных в этой теме. Он использует примеры из MSDN и CodeProject. Спасибо Джеймсу.
Я также сделал модификации, рекомендованные Джоэлем Мюллером.
Код здесь:
https://github.com/dermeister0/LockFreeSessionState
Модуль HashTable:
Модуль ScaleOut StateServer:
Пользовательский модуль:
Если вы хотите реализовать поддержку Memcached или Redis, установите этот пакет. Затем наследуйте класс LockFreeSessionStateModule и реализуйте абстрактные методы.
Некоторые поставщики сеансов без блокировки, использующие Redis:
источник
Если у вашего приложения нет особых потребностей, я думаю, у вас есть 2 подхода:
Сеанс не только поточно-ориентированный, но и защищенный от состояний, так что вы знаете, что до тех пор, пока текущий запрос не будет завершен, каждая переменная сеанса не будет отличаться от другого активного запроса. Для того чтобы это произошло, вы должны убедиться, что сессия будет заблокирована до тех пор, пока текущий запрос не будет завершен.
Вы можете создать поведение, похожее на сеанс, многими способами, но если оно не блокирует текущий сеанс, оно не будет «сеансом».
Для конкретных проблем, которые вы упомянули, я думаю, вы должны проверить HttpContext.Current.Response.IsClientConnected . Это может быть полезно для предотвращения ненужных выполнений и ожидания на клиенте, хотя это не может полностью решить эту проблему, так как это может использоваться только путем объединения, а не асинхронно.
источник
Если вы используете обновленный
Microsoft.Web.RedisSessionStateProvider
(начиная с3.0.2
), вы можете добавить это к себе,web.config
чтобы разрешить одновременные сеансы.Источник
источник
Для ASPNET MVC мы сделали следующее:
SessionStateBehavior.ReadOnly
для всех действий контроллера переопределениеDefaultControllerFactory
SessionStateBehavior.Required
Создайте собственный ControllerFactory и переопределите
GetControllerSessionBehavior
.AcquireSessionLockAttribute
Подключите созданный контроллер фабрики в
global.asax.cs
Теперь мы можем иметь как
read-only
иread-write
состояние сеанса в одномController
.источник
Пометка состояния сеанса контроллера как только для чтения или отключенное решит проблему.
Вы можете украсить контроллер следующим атрибутом, чтобы отметить его только для чтения:
System.Web.SessionState.SessionStateBehavior перечисление имеет следующие значения:
источник
Просто чтобы помочь кому-нибудь с этой проблемой (блокировка запросов при выполнении другого из того же сеанса) ...
Сегодня я начал решать эту проблему и после нескольких часов исследований решил ее, удалив
Session_Start
метод (даже пустой) из Global.asax. файла .Это работает во всех проектах, которые я тестировал.
источник
Session_Start
метода, и он все еще блокируетсяПоработав со всеми доступными опциями, я закончил тем, что написал поставщика SessionStore на основе токенов JWT (сессия проходит внутри cookie, и внутреннее хранилище не требуется).
http://www.drupalonwindows.com/en/content/token-sessionstate
Преимущества:
источник