Beschränkt sich REST nur auf eine optimistische Parallelitätskontrolle?

9

Kontext

Aufgrund der Staatenlosigkeit des REST-Architekturstils, bei der jede Anforderung vollständig für sich steht, speichert der Server niemals Informationen über den Client.

Daher ist eine pessimistische Parallelitätskontrolle nicht geeignet, da der Server speichern müsste, welcher Client die Sperre für eine Ressource erhält. Anschließend wird mithilfe des EtagHeaders eine optimistische Parallelitätssteuerung verwendet . (Übrigens, wie ich dort gefragt habe /programming/30080634/concurrency-in-a-rest-api )

Problem

Das Hauptproblem bei einem optimistischen Mechanismus zur Kontrolle der Parallelität besteht darin, dass Sie jederzeit allen Clients erlauben, alle Vorgänge auszuführen.

Und das möchte ich vermeiden, ohne das Prinzip der Staatenlosigkeit von REST zu brechen. Ich meine, dass nicht alle Clients zu irgendeinem Zeitpunkt eine Operation ausführen können.

Frage

In meinem Kopf, wäre es möglich , mit einem halb optimistisch Nebenläufigkeitssteuermechanismus, wie folgt aus:

  • Clients können ein Token anfordern
  • Es kann nur ein Token generiert werden und hat eine begrenzte Gültigkeitsdauer
  • Um Operationen an Ressourcen (wie POST oder PUT ) auszuführen , muss der Client dieses Token als Teil des Hauptteils (oder Headers?) Der Anforderung angeben. Clients, die nicht über das Token verfügen, können diese Vorgänge nicht ausführen.

Es ist der optimistischen Parallelitätskontrolle sehr ähnlich, außer dass nur ein Client einige Operationen ausführen kann (derjenige, der das Token erhalten hat) ... im Gegensatz zu "Alle Clients können alle Operationen ausführen".

Ist dieser Mechanismus mit einem REST-Architekturstil kompatibel? Bricht es eine seiner Einschränkungen? Ich habe überlegt, nach SO zu fragen, aber dies scheint eher eine allgemeine Frage zu sein, die sich auf das Software-Design bezieht.

AilurusFulgens
quelle
1
Eigentlich ist es ziemlich einfach: Sie müssen eine Transactionexplizit als Ressource modellieren .
Jörg W Mittag
Was ändert sich? Ich bin mir nicht sicher, ob ich deinen Kommentar verstehe. Ich mache keine Parallelitätskontrolle für Transaktionen, sondern um dem Kunden zu sagen "OK, jetzt sind Sie absolut sicher, dass niemand die Ressource ändern würde" (da sie ein eindeutiges Token erhalten hat).
AilurusFulgens
1
Was ist der Unterschied? Auf der einen Seite überprüfen Sie mit dem Etag, wer die "aktuelle" Version aktualisieren darf. Wenn es zu Konflikten kommt, müssen Sie Ihre Version aktualisieren und das Update danach durchführen. Auf der anderen Seite haben Sie Ihren "Verriegelungs" -Mechanismus: Einer ist erlaubt, andere müssen warten. Klingt ziemlich gleich. Der Nachteil des zweiten Ansatzes: 2 Anforderungen - 1 für die Sperre und 1 für das Update. Im optimalen Fall haben Sie nur ein Update über den Etag-Ansatz.
Thomas Junk
Nun, im Allgemeinen geht es um Parallelitätskontrolle ... die Sekunde, in der "das Rennen verloren hat", muss immer warten (nur aus verschiedenen Gründen stimme ich dem zu). Unterschied zu Etag? Wenn EtagSie nie sicher sind, ob Ihre Operationen abgeschlossen sind, können Sie eine Situation haben, in der Sie niemals irgendwelche Operationen ausführen werden. Mit einem Schloss können Sie sicher sein, dass Sie zumindest Ihre Operation ausführen. Eine einfache Sperre ist also nur eine Mitte zwischen einer Umgebung, in der "hohe Konflikte" und "seltene Konflikte" auftreten können.
AilurusFulgens

Antworten:

3

Sie sollten niemals (wie nie zuvor) eine Ressource sperren, während Sie auf eine Benutzerinteraktion warten.

Irgendwann werden einige Ihrer Benutzer für ein langes Wochenende abheben und einige wichtige Datensätze gesperrt lassen.

Ah, aber Sie werden das nicht zulassen, weil Sie ein cleveres Timeout / Deadlock-Auflösungsschema haben. Dann wird dies irgendwann schrecklich schief gehen und ein Benutzer, der eine nette Nachricht "Ihr Widget wurde bestellt" erhalten hat, wird am Helpdesk schreien und fragen, warum sein Widget nicht geliefert wurde.

Die meisten Leute können mit der Nachricht "Entschuldigung, ein anderer Benutzer hat gerade diesen Teil bestellt" umgehen.

James Anderson
quelle
Du hast es schön erklärt. Obwohl ich von Ihrem ersten Satz nicht ganz überzeugt bin: Irgendwann würden Sie garantieren, dass niemand anderes als Sie einen Auftrag ausführen kann. Aber gut, Ihr letzter Satz ist eine gute Zusammenfassung, in 99% der Fälle ist dies der Fall.
AilurusFulgens
1
Wenn Sie einen Datensatz für einen bestimmten Benutzer sperren müssen, tun Sie dies auf Anwendungsebene. Entweder ein einfaches "LockedBy" -Attribut oder ein ausgefeilterer Versions- und Workflow-Mechanismus.
James Anderson
Was meinst du mit "auf Anwendungsebene"? Wenn Sie Ihrer Ressource ein "LockedBy" -Attribut hinzufügen, speichern Sie Informationen zum Client auf Ihrem Server. Oder vielleicht habe ich deinen Kommentar nicht verstanden. Wenn Sie einige Details angeben können, wäre es großartig!
AilurusFulgens
1
@AilurusFulgens - Sie fügen Ihrer Datenbank ein LockedBy-Attribut (und möglicherweise einen LockedOn-Zeitstempel) hinzu. In Ihrem Anwendungscode legen Sie den Benutzernamen und die Uhrzeit fest, wenn der Client eine Aktualisierungsinteraktion startet. Sie deaktivieren es, wenn der Client fertig ist - Sie müssen dann einige Geschäftsregeln ausarbeiten, um Konflikte und Zeitüberschreitungen usw. zu lösen
James Anderson
2

Die Verwendung von Token ist in APIs sehr verbreitet. Diese Token werden normalerweise als Header gesendet und haben einen klaren Lebenszyklus. Denken Sie zum Beispiel an OAuth.

Unabhängig von Ihrer Programmiersprache oder Ihrem Framework sind die REST-APIs ähnlich.

Ich kann mir mehrere Szenarien vorstellen, in denen Sie die Parallelität begrenzen möchten. Zwei davon sind:

  1. Mehrere Clients aktualisieren dieselben Ressourcen wie eine Datenbankzeile. Beispiel: Zwei gleichzeitige Anforderungen, eine löscht einen Datensatz und die andere versucht, denselben Datensatz zu aktualisieren. Abhängig von Ihrer Datenbank und wie Sie sie eingerichtet haben, erhalten Sie möglicherweise eine Sperre für die Datensätze oder einen ungültigen Vorgang, da die Daten unterschiedlich sind oder nicht vorhanden sind.

  2. Ein Superuser oder Administrator, der spezielle Aktionen mit der API ausführt.


Was ist in diesen Fällen zu tun?

  1. Verwenden Sie Transaktionen in der Datenbank, Singletons, Sperren und ähnliche Mechanismen, um den Zugriff auf die Ressourcen zu synchronisieren.

  2. Das Token könnte funktionieren. Ich denke, es ist besser, wenn Sie keine Informationen über den Client speichern, sondern nur über das Token selbst. In einem Schritt können Sie den Benutzer validieren und das Token zuweisen. Überprüfen Sie dann einfach, ob das Token aktiv und gültig ist. Verwenden Sie ein Token, das entschlüsselt werden kann, um zusätzliche Informationen zu erhalten. Sie können speichern, ob dies ein spezielles Token ist, und es jeweils nur zulassen. Auf diese Weise validieren Sie das Token und nicht den Benutzer.

Ich hoffe das hilft.

Pablo Granados
quelle
Ja, ich hatte eine Antwort über die Ähnlichkeit eines Tokens und des OAuth-Mechanismus erwartet. Obwohl der letzte der Authentifizierung gewidmet ist. Ich habe den Punkt Ihres Szenarios 1 nicht verstanden. Der schwierige Teil beim Umgang mit Parallelität in einer REST-API besteht darin, die Einschränkung der Statuslosigkeit beizubehalten ... was bedeutet, dass der Server keine Informationen über den Client speichert. Ihr Szenario 2 ist genau das, was ich gerade mache! :)
AilurusFulgens
Habe ich deine Frage beantwortet?
Pablo Granados
Nein Entschuldigung. Ich habe Ihre Antwort positiv bewertet, weil sie einen guten Überblick über das Problem gibt, aber leider geht es imo nicht wirklich darum.
AilurusFulgens
0

REST alleine ist wirklich zu primitiv. Sie können mit REST beginnen, aber schließlich benötigt Ihre umfangreiche Anwendung Abfragen mit Verknüpfungen und Aktualisierungen mit Transaktionen. Jeder Entwickler, der versucht, diese Dinge selbst hinzuzufügen, wäre fehleranfällig und inkonsistent. Glücklicherweise gibt es einen neuen Standard namens OData, der genau das tut. Es wird über REST gelegt und bietet (1) eine Abfragesprache, die einfache Verknüpfungen mithilfe von Navigationseigenschaften ermöglicht (ohne dass Fremdschlüssel verfügbar gemacht werden müssen), und (2) eine Stapelverarbeitung, die atomare Änderungssätze enthält.

Siehe hier für (1) https://stackoverflow.com/a/3921423/471129 und,

Siehe hier und für (2) https://stackoverflow.com/a/21939972/471129

Erik Eidt
quelle