Generierungsnummern und Vorbedingungen

Mit Objektgenerierungsnummern können Nutzer Datenressourcen eindeutig identifizieren und Vorbedingungen für die Unteilbarkeit mehrstufiger Transaktionen festlegen.

Generierungen

Auch wenn die Objektversionierung deaktiviert ist, haben Cloud Storage-Objekte Generierungsnummern und Meta-Generierungsnummern. Die Generierungsnummer ändert sich jedes Mal, wenn ein Objekt überschrieben wird, und die Meta-Generierungsnummer ändert sich, wenn die Metadaten des Objekts aktualisiert werden.

Da die Meta-Generierungsnummern von Objekten bei jeder neuen Generierung eines Objekts auf 1 zurückgesetzt werden, sind sie nur in Kombination mit einer Generierungsnummer sinnvoll.

Auch Buckets haben eine Meta-Generierungsnummer, anhand der Nutzer den Metadatenstatus eines Buckets genau identifizieren können. Da Buckets keine Nutzlastdaten und somit keine Generierungsnummern haben, sind ihre Meta-Generierungsnummern selbst aussagekräftig.

Beispiel: parallele Uploads

Bei parallelen Uploads teilen Sie ein Objekt in mehrere Teile auf, laden diese Teile gleichzeitig in einen temporären Speicherort hoch und setzen anschließend mit compose das ursprüngliche Objekt aus den Teilen wieder zusammen. Wenn ein hiervon unabhängiger Prozess versehentlich den Namen eines oder mehrerer der temporären Teile verwendet, die Sie hochgeladen haben, werden in der Phase compose falsche Komponenten verwendet und das Objekt wird beschädigt.

Mithilfe von Generierungsnummern können Sie solche Beschädigungen vermeiden. Wenn Sie in die compose-Anfrage die Generierungsnummern aller hochgeladenen Teile aufnehmen, erfolgt die Zusammensetzung compose entweder mit den korrekten Teilen oder schlägt mit der Antwort 404 Not Found fehl.

Vorbedingungen

Mithilfe von Vorbedingungen wird Cloud Storage signalisiert, eine Anfrage nur zu senden, wenn die Generierungsnummer oder Meta-Generierungsnummer des betroffenen Objekts die von Ihnen festgelegten Vorbedingungen erfüllt. Diese Prüfung der Generierungsnummern und Meta-Generierungsnummern gewährleistet, dass sich die Objekte in dem erwarteten Zustand befinden und dass Sie an Objekten sichere Read-Modify-Write-Aktualisierungen und an Bedingungen gebundene Vorgänge ausführen können.

Wenn eine match-Vorbedingung eine bestimmte Generierungsnummer oder Meta-Generierungsnummer verwendet, muss das Cloud Storage-Objekt, auf das sich die Anfrage bezieht, die gleiche Generierungsnummer oder Meta-Generierungsnummer haben. Trifft dies zu, ist die Anfrage erfolgreich. Andernfalls schlägt sie fehl und die Antwort 412 Precondition Failed wird zurückgegeben.

Wenn eine match-Vorbedingung anstelle einer Generierungsnummer den Wert 0 verwendet, ist die Anfrage nur erfolgreich, wenn sich in dem Cloud Storage-Bucket mit dem in der Anfrage angegebenen Namen keine Liveobjekte befinden. Andernfalls schlägt die Anfrage fehl und die Antwort 412 Precondition Failed wird zurückgegeben.

Vorbedingungen werden häufig bei Änderungsanfragen verwendet, wie beim Hochladen, Löschen, Kopieren oder bei Aktualisierungen von Metadaten, um Race-Bedingungen zu vermeiden. Race-Bedingungen können auftreten, wenn dieselbe Anfrage mehrmals gesendet wird oder wenn sich unabhängige Prozesse gegenseitig beeinträchtigen. Derartige Bedingungen können zum Beispiel ausgelöst werden, wenn mehrere Anfrageversuche nach einer Netzwerkunterbrechung gesendet werden oder wenn Read-Modify-Write-Vorgänge (Lesen-Ändern-Schreiben) von Nutzern am selben Objekt ausgeführt werden.

Neben den Vorbedingungen mit Generierungsnummern und Meta-Generierungsnummern gibt es auch Vorbedingungen auf der Grundlage von ETags. XML API-ETags von nicht zusammengesetzten Objekten ändern sich nur, wenn der Inhalt geändert wird, während sich ETags von zusammengesetzten Objekten und JSON API-Ressourcen ändern, wenn der Inhalt oder die Metadaten geändert werden. Weitere Informationen über ETags finden Sie unter Hashes und ETags: Best Practices.

Kosten für Vorbedingungen

Vorbedingungen verursachen Leistungs- und Abrechnungskosten. Bei jedem Änderungsvorgang senden Sie auch eine kostenpflichtige GET-Metadatenanfrage, um die Generierungsnummer und die Meta-Generierungsnummer des Objekts zu ermitteln. Im Hinblick auf die Leistung können Vorbedingungen unter Umständen aufgrund des zusätzlichen Umlaufs den Netzwerkanteil der Gesamtvorgangslatenz verdoppeln, was bei latenzempfindlichen Vorgängen möglicherweise einen bedeutenden Faktor darstellt. Zur Orientierung: Die Metadatenanfrage GET, die die Verwendung von Vorbedingungen ermöglicht, wird mit 0,004 $ pro 10.000 Vorgänge berechnet.

Je nach Anwendung haben Sie jedoch mehrere Möglichkeiten, Leistungs- und Abrechnungskosten im Zusammenhang mit Vorbedingungen einzusparen, wie zum Beispiel:

  • Speichern Sie die Generierungsnummern und Meta-Generierungsnummern Ihrer Objekte lokal, damit Sie die korrekten Nummern zur Verwendung in den Vorbedingungen bereits kennen.
  • Nutzen Sie ein Benennungsschema, bei dem maximal eine Änderung desselben Objektnamens auftritt, sodass Sie keine Vorbedingungen benötigen.
  • Wenn Ihnen klar ist, welche Objekte neu erstellt werden, wissen Sie auch im Voraus, wann die Vorbedingung if-generation-match:0 verwendet werden muss.
  • Behalten Sie die Ergebnisse der GET-Aufrufe im Gedächtnis, die vor den Änderungen ausgeführt wurden.

Vorbedingungen in der XML API

In der XML API werden Generierungs- und Meta-Generierungsnummern über die Antwortheader x-goog-generation und x-goog-metageneration angezeigt. Diese Header werden als Antwort auf eine HEAD-Anfrage für ein Objekt zurückgegeben.

In der HTTP-Header-Referenz finden Sie die vollständige Liste der Header für Anfragen mit Vorbedingungen, die Sie nutzen können, um Anfragen zu erstellen, die an den Status des angeforderten Objekts gebunden sind. Beispiele:

  • Verwenden Sie die Vorbedingung x-goog-if-generation-match, um eine Anfrage nur auszuführen, wenn die Generierungsnummer in der Vorbedingung mit der des angefragten Objekts übereinstimmt. Wenn Sie anstelle einer Generierungsnummer 0 verwenden, ist die Anfrage nur erfolgreich, wenn sich im Bucket mit dem in der Anfrage angegebenen Objekt keine Liveobjekte befinden.

  • Verwenden Sie die Vorbedingung x-goog-if-metageneration-match, um eine Anfrage nur auszuführen, wenn die Meta-Generierungsnummer im Header mit der des angefragten Objekts übereinstimmt.

  • Verwenden Sie die Vorbedingung If-Modified-Since bei GET- oder HEAD-Anfragen. Diese Anfragen werden nur ausgeführt, wenn der Erstellungszeitpunkt der neuesten Generierung des Objekts – also der Zeitpunkt der letzten Änderung – vor der in der Vorbedingung angegebenen Zeit liegt.

  • Verwenden Sie ETags und die Vorbedingung If-Match oder If-None-Match bei GET- oder HEAD-Anfragen. Diese Anfragen werden nur ausgeführt, wenn das angeforderte Objekt mit dem in der Vorbedingung angegebenen ETag übereinstimmt bzw. nicht übereinstimmt.

  • Verwenden Sie mehrere Vorbedingungen in einer Anfrage. Wenn Sie zum Beispiel x-goog-if-generation-match verwenden, können Sie auch x-goog-if-metageneration-match verwenden.

Vorbedingungen in der JSON API

In der JSON API können Sie die Generierungs- und Meta-Generierungsnummern über die Attribute generation und metageneration einer Antwort abrufen, die eine Objekt- oder Bucket-Ressource enthält. Eine Objekt- oder Bucket-Ressource wird im Antworttext einer GET-Anfrage für das Objekt bzw. für den Bucket zurückgegeben.

Um Vorbedingungen in Anfragen zu verwenden, fügen Sie diese als Abfrageparameter an das Ende der URL an. Fügen Sie für jede Vorbedingung einen Abfrageparameter ein, der denselben Namen wie die Vorbedingung hat. Die folgende Anfrage enthält zum Beispiel die Vorbedingung ifGenerationMatch: https://www.googleapis.com/storage/v1/b/testgrid-triage-testing/o/test?ifGenerationMatch=1122334455.

In diesem Beispiel wird die Anfrage von der API nur ausgeführt, wenn die Objektgenerierung 1122334455 entspricht.

Die JSON API unterstützt außerdem HTTP 1.1-ETags und die entsprechenden HTTP-Header If-Match und If-None-Match für alle Ressourcen, einschließlich Buckets, Objekten und ACLs. Jedes Mal, wenn eine Ressource zurückgegeben wird, ist der ETag sowohl im Antwort-Header als auch in der Ressource enthalten.

Nachfolgend finden Sie einige Beispiele für Vorbedingungen, die Sie verwenden können, um Anfragen zu erstellen, die an den Status des abgefragten Objekts gebunden sind.

  • Verwenden Sie die Vorbedingungen ifGenerationMatch und ifGenerationNotMatch, um eine Anfrage nur auszuführen, wenn die Generierungsnummer im Attribut der Generierungsnummer des angeforderten Objekts entspricht bzw. nicht entspricht. Wenn Sie in ifGenerationMatch anstelle einer Generierungsnummer 0 verwenden, ist die Anfrage nur erfolgreich, wenn sich im Bucket mit dem in der Anfrage angegebenen Objekt keine Liveobjekte befinden.

  • Verwenden Sie die Vorbedingungen ifMetagenerationMatch und ifMetagenerationNotMatch, um eine Anfrage für einen Bucket oder ein Objekt auszuführen. Diese Anfragen sind nur erfolgreich, wenn die Meta-Generierungsnummer im Attribut mit der Meta-Generierungsnummer des angeforderten Buckets oder Objekts übereinstimmt bzw. nicht übereinstimmt.

  • Verwenden Sie ETags und die Vorbedingungen If-Match oder If-None-Match als Header in Anfragen. Diese Anfragen werden nur ausgeführt, wenn das angeforderte Objekt mit dem in der Vorbedingung angegebenen ETag übereinstimmt bzw. nicht übereinstimmt.

  • Verwenden Sie mehrere Vorbedingungen in einer Anfrage. Wenn Sie zum Beispiel ifGenerationMatch zum Anfordern eines Objekts verwenden, können Sie auch ifMetagenerationMatch verwenden.

Beachten Sie, dass die Vorbedingungen mit Generierungs- und Meta-Generierungsnummern für ACL-Vorgänge nicht zulässig sind. Verwenden Sie hier stattdessen das ETag der Eintragsressource für die Zugriffssteuerung. Dieses finden Sie in jeder Eintragsressource für die Zugriffssteuerung, die auch über die Objekt- oder Bucket-Ressource zugänglich ist, in der sie enthalten ist.

Beispiele für Race-Bedingungen

Gleichzeitige Read-Modify-Write-Vorgänge (Lesen-Ändern-Schreiben)

Die Aktualisierung von Bucket- oder Objekt-Metadaten erfolgt gewöhnlich nach folgendem Muster: Der aktuelle Status wird gelesen, dann werden Änderungen lokal vorgenommen und schließlich werden die geänderten Metadaten zum Schreiben an Cloud Storage zurückgesendet. Dies kann zu kritischen Situationen führen, wenn zwei oder mehr voneinander unabhängige Prozesse versuchen, diese Sequenz gleichzeitig auszuführen.

Betrachten Sie den folgenden Fall: Sie möchten für eine Mitbearbeiterin einen ACL-Eintrag hinzufügen, damit sie auf Ihren Bucket zugreifen kann. Gleichzeitig möchte ein Kollege einen anderen Mitbearbeiter entfernen, der keinen Zugriff mehr auf den Bucket benötigt.

Hierzu lesen sowohl Sie als auch Ihr Kollege denselben Anfangsstatus der Metadaten des Buckets und nehmen jeweils die gewünschte Änderung an den ACL-Einträgen des Buckets vor. Wenn Sie Ihre Änderungen in Cloud Storage hochladen, werden die Metadaten korrekt aktualisiert. Allerdings gehen sie verloren, sobald Ihr Kollege seine Änderungen hochlädt, weil er keine Möglichkeit hatte, Ihre Aktualisierung zu berücksichtigen. Demzufolge geht der ACL-Eintrag für Ihre Mitbearbeiterin verloren. Sie kann nicht auf den Bucket zugreifen und niemand weiß, was geschehen ist, ohne zurückzugehen und die ACL-Einträge zu prüfen.

Race-Bedingungen verhindern

Sie und Ihr Kollege können dieser Race-Bedingungen vorbeugen, indem Sie jedem Ihrer Schreibvorgänge die Vorbedingung if-metageneration-match hinzufügen. Als Vorbedingung verwenden Sie beide die Meta-Generierungsnummer des Buckets. Diese ist in den Metadaten enthalten, die Sie beim anfänglichen Lesevorgang empfangen haben.

Sobald Sie eine Änderung vornehmen, also den ACL-Eintrag hinzufügen, ändert sich auch die Meta-Generierungsnummer des Buckets. Wenn Sie Vorbedingungen verwenden und Ihr Kollege versucht, seine Version der ACL-Einträge zu schreiben, stimmt die Meta-Generierungsnummer des Buckets nicht mehr mit jener in der Vorbedingung überein und er wird mit dem Antwortcode 412 Precondition Failed über das Fehlschlagen seiner Aktualisierung informiert. Auf der Grundlage dieses Antwortcodes kann Ihr Kollege entsprechend reagieren, indem er einen neuen Read-Modify-Write-Zyklus mit den aktualisierten Metadaten ausführt.

Mehrere Anfrageversuche

Cloud Storage ist ein verteiltes System. Da Anfragen aufgrund von Netzwerk- oder Dienstbedingungen fehlschlagen können, sollten Sie bei Neuversuchen nach Fehlschlägen den exponentiellen Backoff verwenden. Aufgrund der Beschaffenheit verteilter Systeme können diese Neuversuche zu unerwartetem Verhalten führen.

Betrachten Sie den folgenden Fall: Sie möchten die Datei file.txt löschen, die in Cloud Storage gespeichert ist. Anschließend möchten Sie eine neue Datei mit demselben Namen in Cloud Storage hochladen.

Hierzu senden Sie eine Anfrage zum Löschen des Objekts. Aufgrund einer Netzwerkbedingung, wie zum Beispiel durch einen zwischengeschalteten Router, dessen Verbindung vorübergehend getrennt wird, erreicht die Anfrage jedoch Cloud Storage nicht und Sie erhalten keine Antwort.

Da Sie keine Antwort auf die erste Anfrage erhalten haben, senden Sie eine zweite Anfrage zum Löschen des Objekts. Diese ist erfolgreich und Sie erhalten eine Antwort, die das Löschen bestätigt. Eine Minute später beschließen Sie, eine neue file.txt-Datei hochzuladen, und Ihr Upload ist erfolgreich.

Eine Race-Bedingung wird ausgelöst, wenn die Verbindung des zuvor getrennten Routers wiederhergestellt wird und dieser nun Ihre ursprüngliche Anfrage zum Löschen an Cloud Storage sendet. Die Anfrage erreicht Cloud Storage und wird erfolgreich ausgeführt, weil die neue file.txt-Datei vorhanden ist. Cloud Storage sendet eine Antwort, die Sie jedoch nicht erhalten, weil Ihr Client den Vorgang nicht mehr überwacht. Das heißt, es wird nicht nur Ihre neue Datei unerwünscht gelöscht, sondern Sie erfahren auch nichts von dem zweiten Löschvorgang.

Das folgende Diagramm veranschaulicht den Vorgang:

Race-Bedingungen verhindern

Um zu verhindern, dass die oben beschriebene Situation eintritt, rufen Sie zuerst die Metadaten von file.txt ab, um deren aktuelle Generierung zu ermitteln. Senden Sie dann die Löschanfrage mit der Vorbedingung if-generation-match auf Grundlage der Generierungsnummer. Mit der Vorbedingung wird sichergestellt, dass nur das Objekt mit dieser spezifischen Generierungsnummer gelöscht wird, unabhängig von dem Zeitpunkt, zu dem die Anfrage Cloud Storage erreicht, oder der Anzahl der mit der Vorbedingung gesendeten Löschanfragen. Mit der Vorbedingung if-generation-match schlagen alle unbeabsichtigten Versuche, eine andere Generierung von file.txt zu ändern, fehl und es wird der Antwortcode 412 Precondition Failed zurückgegeben.

Ähnliche Netzwerkunterbrechungen können auch nach dem Löschen bei der anschließenden Uploadanfrage Race-Bedingungen auslösen. Viele davon können Sie vermeiden, indem Sie die Uploadanfrage mit der Vorbedingung if-generation-match:0 senden. Diese Vorbedingung gewährleistet, dass bei mehreren Uploadversuchen das Objekt nicht versehentlich zweimal geschrieben wird, weil die Anfrage nur erfolgreich ist, wenn keine weiteren aktuellen Generierungen des Objekts vorhanden sind.

Mit diesen Vorbedingungen schützen Sie sich vor Datenverlust, wenn Sie Lösch- und Uploadanfragen ausführen. Das folgende Diagramm veranschaulicht den Vorgang:

Einschränkungen für if-generation-match:0

Die Vorbedingung if-generation-match:0 verhindert nicht, dass ein Objekt doppelt erstellt wird, wenn das erste Objekt gelöscht wird, weil das Fehlen des Objekts nicht eindeutig ermittelt werden kann. Betrachten Sie den folgenden Fall, in dem zwar keine Daten verloren gehen, aber letztendlich eine Datei erstellt wird, die Sie nicht erwarten.

  1. Sie beginnen mit einer GET-Anfrage für die Metadaten von file.txt, um die Generierungsnummer zu ermitteln. Der Antwort entnehmen Sie, dass file.txt nicht existiert.

  2. Ausgehend von dieser Information senden Sie eine Anfrage zum Hochladen von file.txt mit der Vorbedingung if-generation-match:0. Bei dieser Anfrage tritt jedoch eine Zeitüberschreitung auf, wenn die Verbindung eines zwischengeschalteten Routers vorübergehend getrennt wird.

  3. Nach dem Fehlschlagen des ersten Versuchs senden Sie die Uploadanfrage noch einmal, wieder mit der Vorbedingung if-generation-match:0. Dieses Mal ist die Anfrage erfolgreich.

  4. Kurz danach senden Sie eine Anfrage zum Löschen von file.txt, die korrekt ausgeführt wird.

  5. Wenn der Router, dessen Verbindung getrennt war, diese nun wiedererlangt und Ihre erste Uploadanfrage an Cloud Storage sendet, ist die Vorbedingung dieser ersten Anfrage noch immer erfüllt und file.txt wird neu erstellt. Mit oder ohne Vorbedingung wird file.txt in diesem Fall unerwartet ein zweites Mal hochgeladen.

Hat Ihnen diese Seite weitergeholfen? Teilen Sie uns Ihr Feedback mit:

Feedback geben zu...