Node / Express: Gleichzeitigkeitsprobleme bei der Verwendung der Sitzung zum Speichern des Status

9

Also, ich habe ein bisschen nach diesem gesucht und einige ähnliche Fragen gefunden, von denen keine wirklich das Problem anspricht, also dachte ich, dass das eine eigene Frage verdient.

Ich habe eine Express-Anwendung mit einer Reihe von Routen, die die Sitzung ändern, um den Status beizubehalten. Die Sache ist, wenn es mehrere parallele Anfragen gibt, wird die Sitzung von Zeit zu Zeit aufgrund von Rennbedingungen zwischen Anforderungen überschrieben.

Also normalerweise

%Vor%

Grundsätzlich ist das Problem einfach und liegt z. beschrieben in diese Antwort. Express speichert die Sitzung in res.end (), aber während eine methodA-Anforderung verarbeitet wird, könnte eine MethodeB-Anforderung die Sitzung in der Zwischenzeit geändert haben, sodass bei der Speicherung der Sitzung in MethodeA alle von Methode B vorgenommenen Änderungen überschrieben werden. Obwohl der Knoten also single-threaded ist und alle Anfragen von demselben Thread bedient werden, können Probleme mit der Gleichzeitigkeit auftreten, sobald irgendeine Methode etwas asynchron durchführt und somit andere Anfragen gleichzeitig behandelt.

Ich habe jedoch Schwierigkeiten zu entscheiden, wie ich vorgehen soll, um dieses Problem zu lösen. Alle Antworten, die ich gefunden habe, zeigen nur Wege auf, wie die Wahrscheinlichkeit für dieses Ereignis minimiert, z. indem Sie sicherstellen, dass der statische Inhalt die Sitzung nicht speichert, indem Sie die serve-static MW vor der Sitzung MW registrieren. Aber das hilft nur in gewissem Maße; Wenn es tatsächlich API-Methoden gibt, die parallel aufgerufen werden sollen, ist ein echter Concurrency-Ansatz für Sitzungsaktualisierungen erforderlich (IMO, wenn es um Gleichzeitigkeitsprobleme geht, jede "Lösung", die versucht, die Wahrscheinlichkeit von Problemen zu minimieren statt zu adressieren) das eigentliche Problem wird zwangsläufig schief gehen.)

Im Grunde sind das die Alternativen, die ich bisher erkundet habe:

  1. Verhindern Sie parallele Anforderungen innerhalb derselben Sitzung vollständig, indem Sie meinen Client so ändern, dass er alle API-Methoden seriell aufruft.

    Dies ist zwar möglich, hat aber einige Auswirkungen auf meine Architektur und kann die Leistung beeinträchtigen. Es vermeidet auch das Problem, anstatt es zu lösen, und wenn ich etwas falsch in meinem Client mache oder die API von einem anderen Client verwendet wird, kann ich immer noch zufällig darauf stoßen, also fühlt es sich nicht sehr robust an.

  2. Stellen Sie sicher, dass jedem Sitzungs-Schreibvorgang ein Sitzungs-Reload vorausgeht, und machen Sie den gesamten reload-modify-write-Vorgang zu einem atomaren Vorgang.

    Ich bin mir nicht sicher, wie ich das erreichen soll. Selbst wenn ich res.end () modifiziere, um die Sitzung nur neu zu laden, bevor ich sie modifiziere und speichere, weil das Lesen und Schreiben der Sitzung Async-I / O ist, könnte dies passieren:

    • request A lädt die Sitzung neu
    • request A ändert session.A = 'foo'
    • request B lädt die Sitzung neu (und sieht session.A) nicht
    • Anfrage A speichert die Sitzung
    • Anfrage B modifiziert session.B = 'bar'
    • Anfrage B speichert die Sitzung und überschreibt den vorherigen Speicher, sodass session.A fehlt

Also müsste ich im Grunde jedes Atom neu laden, modifizieren - speichern, was im Grunde bedeutet, den Thread zu blockieren? Fühlt sich falsch, und ich habe keine Ahnung, wie es geht.

  1. Verwenden Sie die Sitzung nicht mehr auf diese Weise und übergeben Sie den erforderlichen Status als Parameter an jede Anforderung oder auf andere Weise.

    Dies vermeidet auch das Problem, anstatt es anzugehen. Es hätte auch großen Einfluss auf mein Projekt. Aber sicher, es könnte der beste Weg sein.

  2. ???

Hat jemand irgendwelche Ideen, wie man das auf eine robuste Art angeht? Danke!

    
JHH 19.02.2015, 09:03
quelle

1 Antwort

0

Eine mögliche Lösung hierfür ist die Erstellung einer einfachen Middleware für Express, die eine Liste aller aktuellen Anfragen verwaltet und alle Anfragen aus der gleichen Sitzung in die Warteschlange stellt. Es wird next () nicht aufrufen, bis die vorherigen Anforderungen für diese Sitzungs-ID zuerst verarbeitet wurden.

Jedes Mal, wenn eine Anfrage eingeht, kann sie in einem Objekt gespeichert werden, wobei der Schlüssel der Sitzungs-ID-Cookie-Name und der Wert ein Array aktueller Anfragen für die Sitzungs-ID ist.

{ 'session-id1': [... queued requests ...], 'session-id2': ... }

Wenn eine Anfrage abgeschlossen ist, wird sie sich selbst aus dem Array entfernen und die nächste Anfrage in dem zu bearbeitenden Array auslösen.

Sie können auch jeder Anfrage in der Kopfzeile ein Flag hinzufügen, um die gleichzeitige Ausführung von Anfragen zu ermöglichen, die nicht in die Warteschlange gestellt werden müssen (sie schreiben beispielsweise nicht in die Sitzung), wodurch die Leistung verbessert wird, wenn keine Warteschlangen benötigt werden .

Sie sollten dies implementieren können, ohne Ihre Anwendung ändern zu müssen. Sie könnten auch die Opt-Out-Option in der Kopfzeile auf eine Opt-In-Option ändern, was bedeutet, dass sie alle Anfragen gleichzeitig verarbeitet, so wie sie es normalerweise tun würden, sofern nicht anders angegeben.

    
Zaptree 06.12.2015 16:32
quelle