Ich habe gerade festgestellt, dass jede Anforderung in einer ASP.Net-Webanwendung zu Beginn einer Anforderung eine Sitzungssperre erhält und diese am Ende der Anforderung freigibt!
Falls die Auswirkungen auf Sie verloren gehen, wie es zunächst für mich der Fall war, bedeutet dies im Grunde Folgendes:
Immer wenn das Laden einer ASP.Net-Webseite lange dauert (möglicherweise aufgrund eines langsamen Datenbankaufrufs oder was auch immer) und der Benutzer entscheidet, dass er zu einer anderen Seite navigieren möchte, weil er das Warten satt hat, KÖNNEN SIE NICHT! Die ASP.Net-Sitzungssperre zwingt die neue Seitenanforderung zu warten, bis die ursprüngliche Anforderung schmerzhaft langsam geladen wurde. Arrrgh.
Immer wenn ein UpdatePanel langsam geladen wird und der Benutzer beschließt, zu einer anderen Seite zu navigieren, bevor das UpdatePanel die Aktualisierung abgeschlossen hat ... SIE KÖNNEN NICHT! Die ASP.net-Sitzungssperre zwingt die neue Seitenanforderung zu warten, bis die ursprüngliche Anforderung schmerzhaft schmerzhaft geladen wurde. Double Arrrgh!
Welche Möglichkeiten gibt es? Bisher habe ich mir Folgendes ausgedacht:
- Implementieren Sie einen benutzerdefinierten SessionStateDataStore, den ASP.Net unterstützt. Ich habe nicht zu viele gefunden, um sie zu kopieren, und es scheint ein hohes Risiko zu sein und leicht durcheinander zu bringen.
- Behalten Sie den Überblick über alle laufenden Anforderungen. Wenn eine Anforderung vom selben Benutzer eingeht, brechen Sie die ursprüngliche Anforderung ab. Scheint irgendwie extrem, aber es würde funktionieren (glaube ich).
- Verwenden Sie keine Sitzung! Wenn ich einen Status für den Benutzer benötige, kann ich stattdessen einfach Cache und Schlüsselelemente für den authentifizierten Benutzernamen oder ähnliches verwenden. Scheint wieder irgendwie extrem.
Ich kann wirklich nicht glauben, dass das ASP.Net Microsoft-Team bei Version 4.0 einen so großen Leistungsengpass im Framework hinterlassen hätte! Vermisse ich etwas Offensichtliches? Wie schwierig wäre es, eine ThreadSafe-Sammlung für die Sitzung zu verwenden?
Antworten:
Wenn Ihre Seite keine Sitzungsvariablen ändert, können Sie den größten Teil dieser Sperre deaktivieren.
Wenn Ihre Seite keine Sitzungsvariablen liest, können Sie diese Sperre für diese Seite vollständig deaktivieren.
Wenn keine Ihrer Seiten Sitzungsvariablen verwendet, deaktivieren Sie einfach den Sitzungsstatus in der Datei web.config.
Ich bin gespannt, was würde "eine ThreadSafe-Sammlung" Ihrer Meinung nach tun, um threadsicher zu werden, wenn keine Sperren verwendet werden?
Bearbeiten: Ich sollte wahrscheinlich erklären, was ich mit "Deaktivieren des größten Teils dieser Sperre" meine. Eine beliebige Anzahl von Seiten mit schreibgeschützter Sitzung oder ohne Sitzung kann für eine bestimmte Sitzung gleichzeitig verarbeitet werden, ohne sich gegenseitig zu blockieren. Eine Lese- / Schreibsitzungsseite kann jedoch erst mit der Verarbeitung beginnen, wenn alle schreibgeschützten Anforderungen abgeschlossen sind. Während der Ausführung muss sie exklusiven Zugriff auf die Sitzung dieses Benutzers haben, um die Konsistenz aufrechtzuerhalten. Das Sperren einzelner Werte würde nicht funktionieren, denn was ist, wenn eine Seite eine Reihe verwandter Werte als Gruppe ändert? Wie würden Sie sicherstellen, dass andere Seiten, die gleichzeitig ausgeführt werden, eine konsistente Ansicht der Sitzungsvariablen des Benutzers erhalten?
Ich würde vorschlagen, dass Sie versuchen, die Änderung von Sitzungsvariablen zu minimieren, sobald sie festgelegt wurden, wenn dies möglich ist. Auf diese Weise können Sie den Großteil Ihrer Seiten schreibgeschützt machen, wodurch sich die Wahrscheinlichkeit erhöht, dass sich mehrere gleichzeitige Anforderungen desselben Benutzers nicht gegenseitig blockieren.
quelle
<pages enableSessionState="ReadOnly" />
Option zum Deaktivieren ist web.config. Verwenden Sie @Page, um das Schreiben nur auf bestimmten Seiten zu aktivieren.OK, so große Requisiten an Joel Muller für all seine Beiträge. Meine ultimative Lösung bestand darin, das am Ende dieses MSDN-Artikels beschriebene benutzerdefinierte SessionStateModule zu verwenden:
http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstateutility.aspx
Das war:
Dies hat einen RIESIGEN Unterschied zum Gefühl der "Schnelligkeit" unserer Anwendung gemacht. Ich kann immer noch nicht glauben, dass die benutzerdefinierte Implementierung von ASP.Net Session die Sitzung für die gesamte Anforderung sperrt. Dies verleiht Websites eine so große Trägheit. Gemessen an der Menge an Online-Recherchen, die ich durchführen musste (und an Gesprächen mit mehreren wirklich erfahrenen ASP.Net-Entwicklern), haben viele Menschen dieses Problem erlebt, aber nur sehr wenige Menschen sind jemals der Sache auf den Grund gegangen. Vielleicht schreibe ich einen Brief an Scott Gu ...
Ich hoffe das hilft ein paar Leuten da draußen!
quelle
ReaderWriterLock
wurde er zugunsten von abgelehntReaderWriterLockSlim
- Sie sollten ihn stattdessen verwenden. Zweitenslock (typeof(...))
wurde auch veraltet - Sie sollten stattdessen eine private statische Objektinstanz sperren. Drittens ist der Ausdruck "Diese Anwendung verhindert nicht, dass gleichzeitige Webanforderungen dieselbe Sitzungskennung verwenden" eine Warnung und keine Funktion.SessionStateItemCollection
im Beispielcode durch eine thread-sichere Klasse (möglicherweise basierend aufConcurrentDictionary
) ersetzen, wenn Sie schwer zu reproduzierende Fehler unter Last vermeiden möchten.ISessionStateItemCollection
verlange leider, dass dieKeys
Eigenschaft vom Typ istSystem.Collections.Specialized.NameObjectCollectionBase.KeysCollection
- der keine öffentlichen Konstrukteure hat. Danke Jungs. Das ist sehr praktisch.Ich habe angefangen, das AngiesList.Redis.RedisSessionStateModule zu verwenden . Abgesehen von der Verwendung des (sehr schnellen) Redis-Servers für die Speicherung (ich verwende den Windows-Port - obwohl es auch einen MSOpenTech-Port gibt ) wird die Sitzung absolut nicht gesperrt .
Meiner Meinung nach ist dies kein Problem, wenn Ihre Anwendung angemessen strukturiert ist. Wenn Sie im Rahmen der Sitzung tatsächlich gesperrte, konsistente Daten benötigen, sollten Sie selbst eine Sperr- / Parallelitätsprüfung durchführen.
Die Entscheidung von MS, dass jede ASP.NET-Sitzung standardmäßig gesperrt werden sollte, um mit schlechtem Anwendungsdesign umzugehen, ist meiner Meinung nach eine schlechte Entscheidung. Vor allem, weil es den Anschein hat, als hätten die meisten Entwickler nicht einmal bemerkt, dass Sitzungen gesperrt waren, geschweige denn, dass Apps anscheinend so strukturiert sein müssen, dass Sie den Status einer schreibgeschützten Sitzung so weit wie möglich festlegen können (Opt-out, wo möglich). .
quelle
Ich habe eine Bibliothek basierend auf Links in diesem Thread vorbereitet. Es werden die Beispiele von MSDN und CodeProject verwendet. Danke an James.
Ich habe auch Änderungen vorgenommen, die von Joel Mueller empfohlen wurden.
Code ist hier:
https://github.com/dermeister0/LockFreeSessionState
HashTable-Modul:
ScaleOut StateServer-Modul:
Benutzerdefiniertes Modul:
Wenn Sie die Unterstützung von Memcached oder Redis implementieren möchten, installieren Sie dieses Paket. Erben Sie dann die LockFreeSessionStateModule- Klasse und implementieren Sie abstrakte Methoden.
Einige sperrfreie Sitzungsanbieter, die Redis verwenden:
quelle
Ich denke, Sie haben zwei Ansätze, es sei denn, Ihre Bewerbung hat spezielle Anforderungen:
Die Sitzung ist nicht nur threadsicher, sondern auch zustandsicher, sodass Sie wissen, dass sich jede Sitzungsvariable bis zum Abschluss der aktuellen Anforderung nicht von einer anderen aktiven Anforderung ändert. Dazu müssen Sie sicherstellen, dass die Sitzung gesperrt wird, bis die aktuelle Anforderung abgeschlossen ist.
Sie können ein sitzungsähnliches Verhalten auf viele Arten erstellen. Wenn die aktuelle Sitzung jedoch nicht gesperrt wird, handelt es sich nicht um eine Sitzung.
Für die spezifischen Probleme, die Sie erwähnt haben, sollten Sie HttpContext.Current.Response.IsClientConnected überprüfen . Dies kann nützlich sein, um unnötige Ausführungen und Wartezeiten auf dem Client zu verhindern, obwohl dieses Problem nicht vollständig gelöst werden kann, da dies nur auf Pool-Weise und nicht asynchron verwendet werden kann.
quelle
Wenn Sie die aktualisierte Version
Microsoft.Web.RedisSessionStateProvider
(ab3.0.2
) verwenden, können Sie diese zu Ihrer hinzufügenweb.config
, um gleichzeitige Sitzungen zuzulassen.Quelle
quelle
Für ASPNET MVC haben wir Folgendes getan:
SessionStateBehavior.ReadOnly
wird die Aktion aller Controller durch Überschreiben festgelegtDefaultControllerFactory
SessionStateBehavior.Required
Erstellen Sie eine benutzerdefinierte ControllerFactory und überschreiben Sie diese
GetControllerSessionBehavior
.AcquireSessionLockAttribute
Schließen Sie die erstellte Controller-Factory an
global.asax.cs
Jetzt können wir beide
read-only
und denread-write
Sitzungsstatus in einem einzigen habenController
.quelle
Wenn Sie den Sitzungsstatus eines Controllers als schreibgeschützt oder deaktiviert markieren, wird das Problem behoben .
Sie können einen Controller mit dem folgenden Attribut dekorieren, um ihn als schreibgeschützt zu markieren:
Die Aufzählung System.Web.SessionState.SessionStateBehavior hat die folgenden Werte:
quelle
Nur um jemandem bei diesem Problem zu helfen (Sperren von Anforderungen, wenn eine andere aus derselben Sitzung ausgeführt wird) ...
Heute habe ich begonnen, dieses Problem zu lösen, und nach einigen Stunden Recherche habe ich es gelöst, indem ich die
Session_Start
Methode (auch wenn sie leer ist) aus Global.asax entfernt habe Datei .Dies funktioniert in allen Projekten, die ich getestet habe.
quelle
Session_Start
Methode und sperrt immer nochNachdem ich mit allen verfügbaren Optionen zu kämpfen hatte, schrieb ich schließlich einen JWT-Token-basierten SessionStore-Anbieter (die Sitzung wird in einem Cookie gespeichert und es wird kein Backend-Speicher benötigt).
http://www.drupalonwindows.com/de/content/token-sessionstate
Vorteile:
quelle