[JAVA] So implementieren Sie optimistisches Sperren in der REST-API

Überblick

Das Ändern des Status einer Ressource ist eine Operation, die auf einem beliebigen System implementiert ist. Zu diesem Zeitpunkt ist unter Berücksichtigung der Integritätsgarantie eine Art Verriegelungsmechanismus erforderlich.

Unter Bezugnahme auf Zalando stellen wir hier die Konsistenz durch optimistisches Sperren beim Aktualisieren der RESTful-API sicher. Mal sehen, was die Idee in diesem Fall ist. Danach werden wir überlegen, was passieren würde, wenn wir tatsächlich optimistisches Sperren implementieren würden, und die Teile, die in Zalando nicht klar angegeben sind.

So implementieren Sie eine optimistische Sperre

Zalandos Leitfaden zur RESTful-API bietet vier Möglichkeiten, um ein optimistisches Sperren zu erreichen.

Mal sehen, wie diese vier optimistische Sperren realisieren, wenn Listeninformationen über die API abgerufen und eine davon aktualisiert werden.

If-Match-Header und ETag-Header

Der Aktualisierungsablauf und der optimistische Sperrablauf sind in der folgenden Abbildung dargestellt. Überprüfen Sie die Übereinstimmung / Nichtübereinstimmung zwischen dem Wert, der im Teil "Rückgabe mit Etag-Header" an die Clientseite zurückgegeben wurde, und dem Wert, der im Update "If-Match" mit dem "If-Match-Header" angegeben wurde, und sehen Sie sich den API-Server an. Entscheidet, ob aktualisiert werden soll.

If-Match-and-Etag.png

ETags in der Ergebnisentität

Der Aktualisierungsablauf und der optimistische Sperrablauf sind in der folgenden Abbildung dargestellt. Verwenden Sie "Rückgabeliste", um alle Ressourcen abzurufen, die dem entsprechenden Endpunkt zugeordnet sind. Setzen Sie zu diesem Zeitpunkt den Wert jeder Ressource auf Startwert, erstellen Sie ein Etag mit einem Algorithmus und nehmen Sie es in die Antwort auf. Auf dem API-Server ist eine Aktualisierung möglich, abhängig davon, ob der Wert für "If-Match" in "Update" mit "If-Match-Header" und der neu berechnete etag-Wert der Ressource, die die Aktualisierung angefordert hat, identisch sind. Urteilen.

結果エンティティにおけるETags.png

Versionsnummer

Der Aktualisierungsablauf und der optimistische Sperrablauf sind in der folgenden Abbildung dargestellt. Der Client gibt eine Liste mit der Versionsnummer zurück und erfasst alle Ressourcen, die dem entsprechenden Endpunkt im Formular zugeordnet sind, einschließlich der Versionsnummer. Der API-Server bestimmt, ob das Update möglich ist oder nicht, basierend darauf, ob die von update gesendete Versionsnummer und die Versionsnummer der Ressource, für die das Update angefordert wurde, identisch sind. Wenn es aktualisiert wird, wird die Versionsnummer der entsprechenden Ressource erhöht.

バージョン番号.png

Last-Modified / If-Unmodified-Since Der Aktualisierungsablauf und der optimistische Sperrablauf sind in der folgenden Abbildung dargestellt. Der Client gibt eine Liste mit dem Header "Last-Modified" zurück, um alle Ressourcen abzurufen, die dem entsprechenden Endpunkt zugeordnet sind. Fügen Sie zu diesem Zeitpunkt das Datum und die Uhrzeit der letzten Änderung der Ressource in den Header "Zuletzt geändert" ein. Der API-Server vergleicht das Datum und die Uhrzeit, die mit "If-Unmodified-Since" (= der Wert von "Last-Modified") gesendet wurden, mit dem Datum und der Uhrzeit der letzten Aktualisierung der Ressource, für die die Aktualisierungsanforderung gestellt wurde, und bestimmt, ob die Aktualisierung möglich ist oder nicht. .. (Wenn das Datum und die Uhrzeit der letzten Aktualisierung der Ressource neuer sind, wird davon ausgegangen, dass sie nicht aktualisiert werden kann.)

Last-Modified_If-Unmodified-Since.png

Vor- und Nachteile jeder Methode

So erreichen Sie eine optimistische Sperre verdienen Fehler
If-Match-Header und ETag-Header ・ RESTful Lösung ・ Die Anzahl der Anfragen erhöht sich
ETags in der Ergebnisentität ・ Perfekter optimistischer Rock -Informationen, die dem HTTP-Header hinzugefügt werden sollen, werden in das Geschäftsobjekt übernommen
Versionsnummer ・ Perfekter optimistischer Rock -Informationen, die dem HTTP-Header hinzugefügt werden sollen, werden in das Geschäftsobjekt übernommen
Last-Modified / If-Unmodified-Since ・ Da es schon lange verwendet wird, hat es eine nachgewiesene Erfolgsbilanz.
・ Beeinträchtigt keine Geschäftsobjekte
・ Einfach zu implementieren
・ Keine weiteren Anforderungen außer Aktualisierungsanforderungen erforderlich
-Wenn die API-Seite aus mehreren Instanzen besteht, ist eine strikte Zeitsynchronisation erforderlich.

Ein konkretes Beispiel für ein optimistisches Sperren durch ETags in einer Ergebnisentität

Die folgende Quelle implementiert die Listenerfassung und -aktualisierung mit dem Endpunkt "optimistic / etag". https://github.com/nannany/optimistic-lock-demo Die ETag-Generierung erfolgt mit sha256 wie folgt.


package nannany.optimistic.demo.util;

import com.google.common.hash.Hashing;

import static java.nio.charset.StandardCharsets.UTF_8;

public final class DemoUtils {

    @SuppressWarnings("UnstableApiUsage")
    public static String getHash(String origin) {
        return Hashing.sha256().hashString(origin, UTF_8).toString();
    }
}

Wie im folgenden GIF gezeigt, ist die Aktualisierung erfolgreich, wenn die ETag-Werte übereinstimmen, und wenn sie nicht übereinstimmen, wird 409 zurückgegeben.

etag2019-09-23 17-43.gif

Spezifisches Beispiel für ein optimistisches Sperren durch "Last-Modified / If-Unmodified-Since"

Die folgende Quelle implementiert die Listenerfassung und -aktualisierung mit dem Endpunkt "optimistic / lastModify". https://github.com/nannany/optimistic-lock-demo Das Datum und die Uhrzeit der Erfassung der Liste werden am Datum und der Uhrzeit der letzten Aktualisierung eingegeben, und es wird eine optimistische Sperrung durchgeführt, um festzustellen, ob danach Aktualisierungen an der Ressource vorgenommen wurden.

Wie im folgenden GIF gezeigt, ist die Aktualisierung erfolgreich, wenn das Datum und die Uhrzeit der letzten zu aktualisierenden Ressource der zu aktualisierenden Ressource vor dem Datum und der Uhrzeit liegen, die im Header "If-Unmodified-Since" empfangen wurden. Andernfalls wird 412 zurückgegeben.

lastModify2019-09-23 17-55.gif

Erwägung

Betrachten wir einige der optimistischen Sperrtechniken, die in Zalando nicht spezifiziert sind.

Über den Unterschied zwischen ETags und Versionsnummer in der Ergebnisentität

In Zalando beide der beiden oben genannten Methoden Vorteile: Perfekter optimistischer Rock Nachteil: Informationen, die dem HTTP-Header hinzugefügt werden sollen, gelangen in das Geschäftsobjekt Es gibt keinen klaren Unterschied zwischen Vor- und Nachteilen. (Ich bin mir nicht sicher über den perfekten optimistischen Rock, da es keine detaillierte Erklärung gibt)

Wir glauben, dass die Unterschiede zwischen den Vor- und Nachteilen dieser beiden Methoden die folgenden zwei Punkte sind.

Sollte der API-Server ein Element enthalten, um optimistische Sperren zu erkennen?

Bei beiden Methoden enthalten die an den Client zurückgegebenen Listeninformationen Elemente (ETag und Version) außerhalb des Geschäftsobjekts. Auf der API-Serverseite kann der Wert von ETag jedoch einen Wert des Geschäftsobjekts als Startwert generieren, dh es ist nicht erforderlich, den Wert von ETag zu speichern, während der Wert der Version auf der API-Serverseite gespeichert wird. Muss erledigt werden. Wenn Sie sich dagegen entscheiden, den ETag-Wert nicht auf der API-Serverseite beizubehalten, müssen Sie den ETag jedes Mal berechnen, wenn Sie die Listeninformationen erhalten. Daher müssen Sie prüfen, ob er hinsichtlich der Leistung in Ordnung ist. Korrekt.

Wenn ich darüber nachdenke, wie man die Persistenzinformationen vereinfacht und was man mit der Leistung macht, denke ich, dass dies ein Verdienst und ein Fehler ist.

Schwierigkeit, den Wert zu erraten, um zu beurteilen, ob ein Update durchgeführt werden soll

Die Versionsnummer ist im Grunde ein Wert, der bei jedem Update um 1 erhöht wird, und es ist relativ einfach, die Versionsnummer zu erraten, die aktualisiert werden kann. Andererseits erfordert das Ableiten des Werts von ETag den für die ETag-Generierung verwendeten Algorithmus, den beim Generieren von ETag verwendeten Startwert und den Wert des Startwerts zum Zeitpunkt der Aktualisierung, was schwieriger ist als das Ableiten der Versionsnummer. Es gilt als.

Wenn ich an Sicherheit denke, denke ich, dass dies ein Verdienst und ein Fehler ist.

Über den Sicherheitsaspekt von "Last-Modified / If-Unmodified-Since"

Wenn Sie in "Last-Modified / If-Unmodified-Since" den Wert des Headers "If-Unmodified-Since" von der Clientseite aus neu schreiben und die Zukunft weit voraus angeben (z. B. 31. Dezember 9999), die Ressource Selbst wenn der Wert seit "Zuletzt geändert" aktualisiert wurde, kann er von oben aktualisiert werden.

Aus Sicherheitsgründen halte ich "Last-Modified / If-Unmodified-Since" daher nicht für stark.

Zusammenfassung

Ich habe mir die in Zalando aufgeführte optimistische Sperrmethode angesehen, aber am Ende dachte ich, ich hätte keine andere Wahl, als mir eine Methode auszudenken, die den Anforderungen des von mir erstellten Systems entspricht. Die Tatsache, dass Zalando auch vier Methoden einführt, bedeutet, dass nicht für jedes System die beste optimistische Methode zur Implementierung von Sperren entwickelt wurde.

Anstatt darüber nachzudenken, wie die optimistische Sperre der RESTful-API von 0 implementiert werden soll, wird empfohlen, sie unter Bezugnahme auf die Beschreibung von Zalando usw. zu implementieren und die eingeführten Vor- und Nachteile auf Ihr eigenes System anzuwenden. Ist es nicht eine realistische Lösung?

Referenz

Zalando Tagebuch der Wissenschaftsstudenten RFC7232

Recommended Posts

So implementieren Sie optimistisches Sperren in der REST-API
Implementieren Sie die REST-API mit Spring Boot
So implementieren Sie die Datumsberechnung in Java
So implementieren Sie den Kalman-Filter mit Java
So erzwingen Sie Codierungskonventionen in Java
So implementieren Sie Ranking-Funktionen in Rails
So implementieren Sie die asynchrone Verarbeitung in Outsystems
So implementieren Sie einen Job, der die Java-API in JobScheduler verwendet
So implementieren Sie eine ähnliche Funktion in Rails
So implementieren Sie Paginierung in GraphQL (für Ruby)
So implementieren Sie UICollectionView mit Code nur in Swift
So implementieren Sie die Gastanmeldung in 5 Minuten im Rails-Portfolio
So implementieren Sie eine nette Funktion in Ajax mit Rails
Führen Sie swagger-ui in die in Spring Boot implementierte REST-API ein
Zusammenfassung der Implementierung von Standardargumenten in Java
Verwendung der Ketten-API
Einführung in die EHRbase 2-REST-API
[Rails] So implementieren Sie Scraping
[Java] So implementieren Sie Multithreading
Aufrufen und Verwenden der API in Java (Spring Boot)
So implementieren Sie eine einzeilige Anzeige von TextView in der Android-Entwicklung
Lassen Sie uns herausfinden, wie Sie mit Request Body mit der REST-API von Spring Boot empfangen können
Wie man Lombok im Frühling benutzt
So finden Sie May'n in XPath
So blenden Sie die Bildlaufleiste in WebView aus
Wie man in Ruby auf unbestimmte Zeit iteriert
Versuchen Sie, Yuma in Ruby zu implementieren
Wie man Ant in Gradle ausführt
Wie man die Programmierung in 3 Monaten beherrscht
Wie man JAVA in 7 Tagen lernt
So installieren Sie Bootstrap in Ruby
Verwendung von InjectorHolder in OpenAM
So installieren Sie jQuery in Rails 6
[Rails] So implementieren Sie die Sternebewertung
Wie verwende ich Klassen in Java?
So benennen Sie Variablen in Java
So setzen Sie Lombok in Eclipse
Versuchen Sie, Yuma in Java zu implementieren
So verketten Sie Zeichenfolgen mit Java
So installieren Sie Swiper in Rails
[RubyOnRails] Implementieren eines Pulldowns für form_with basierend auf Tabellendaten
[swift5] So legen Sie die Farbe hexadezimal fest
So erstellen Sie Ihre eigene kopflose API mit Liferays REST Builder (Teil 3)
So erstellen Sie Ihre eigene kopflose API mit Liferays REST Builder (Teil 2)
Mehrsprachige Unterstützung für Java Verwendung des Gebietsschemas
So ändern Sie den App-Namen in Rails
Implementieren Sie API Gateway Lambda Authorizer in Java Lambda
Verwendung des benannten Volumes in docker-compose.yml
Versuchen Sie, n-ary Addition in Java zu implementieren
So filtern Sie den JUnit-Test in Gradle
So fügen Sie ein Video in Rails ein
Wie kann ich Spring Tool in Eclipse 4.6.3 einbinden?
So fügen Sie eine JAR-Datei in ScalaIDE hinzu