Generierungsnummern und Vorbedingungen

Mit Objektgenerierungsnummern können Nutzer Datenressourcen eindeutig identifizieren und Vorbedingungen anwenden, um Datenschäden oder Race-Bedingungen zu verhindern.

Generierungen

Alle Cloud Storage-Objekte haben das Attribut generation und das Attribut metageneration, das sie eindeutig identifiziert:

Attribut Beschreibung
generation Ermittelt die Version eines Objekts und existiert für jedes Objekt, unabhängig davon, ob ein Bucket die Objektversionsverwaltung verwendet.
  • Die generation-Nummer einer Objektversion ändert sich nie. Ein neues Objekt mit dem gleichen Namen kann ein vorhandenes Objekt ersetzen, wobei dem neuen Objekt immer eine andere generation zugewiesen wird.
  • Es gibt keine Garantie dafür, dass die Generierungsnummern für aufeinanderfolgende Versionen erhöht werden, nur dass jede neue Version eine eindeutige Generierungsnummer hat.
  • Zwischen den Generierungsnummern unabhängiger Objekte besteht keinerlei Zusammenhang, selbst wenn sich diese im selben Bucket befinden.
metageneration Gibt die Metadatenversion an und erhöht sich jedes Mal, wenn die Metadaten für eine bestimmte generation aktualisiert werden.
  • metageneration beginnt bei 1 für jede neue generation eines Objekts.
  • Das Attribut metageneration ist ohne das Attribut generation bedeutungslos und sollte daher nur zusammen mit diesem verwendet werden. Es ist bedeutungslos, die Metadatengenerierungen zweier Objektversionen zu vergleichen.

Diese Attribute sind nützlich als Vorbedingungen in bedingten Aktualisierungen, um die Sortierung von Aktualisierungen zu erzwingen. Das Attribut generation ist erforderlich, um mit nicht aktuellen Objekten zu arbeiten.

Ein Beispiel dafür, wie Sie die Metadaten eines Objekts abrufen, einschließlich seiner Generierungsnummer, finden Sie unter Objektmetadaten ansehen und bearbeiten.

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 an 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 von Ihnen hochgeladenen temporären Teile verwendet, 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.

Preconditions

Mithilfe von Vorbedingungen wird Cloud Storage signalisiert, eine Anfrage nur zu senden, wenn die Generierungsnummer oder Meta-Generierungsnummer des betreffenden 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 die Anfrage fehl und die Fehlermeldung 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 Live-Objekte befinden. Die Match=0-Vorbedingung kann für GET-Anfragen verwendet werden. Aber selbst, wenn die Vorbedingung erfolgreich ist, schlägt die gesamte Anfrage möglicherweise fehl, wenn sie ungültig ist. Wenn Sie beispielsweise versuchen, ein nicht vorhandenes Objekt herunterzuladen, während Sie Match=0 verwenden, wird die Antwort 404 zurückgegeben.

Wenn eine NotMatch-Vorbedingung eine Generierungs- oder Meta-Generationsnummer verwendet, die dem Wert eines vorhandenen Cloud Storage-Objekts entspricht, wird die Antwort 304 zurückgegeben.

Vorbedingungen werden häufig bei Änderungsanfragen verwendet, wie beim Hochladen, Löschen, Kopieren oder Aktualisieren 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-Abrufe 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 angeforderten 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 Live-Objekte 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 angeforderten 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 beispielsweise x-goog-if-generation-match verwenden, können Sie auch x-goog-if-metageneration-match verwenden.

Beschränkungen

Vorbedingungen können nicht in mehrteiligen XML API-Uploads verwendet werden. Bei einem entsprechenden Versuch wird ein Fehler ausgegeben.400 NotImplemented

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 Objektressource 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.

Die folgenden Beispiele zeigen, wie die Informationen eines Objekts mithilfe von JSON API-Anfragen und Abfrageparametern als Vorbedingungen abgerufen werden. Sie können die Abfrageparameter ifGenerationMatch, ifGenerationNotMatch, ifMetagenerationMatch und ifMetagenerationNotMatch für Vorgänge wie compose, insert oder rewrite verwenden. Weitere Informationen finden Sie auf der Referenzseite für JSON API-Objekte.

ifGenerationMatch

Bei dieser JSON API-Anfrage wird die Vorbedingung ifGenerationMatch verwendet. Die API schließt diese Anfrage für das Objekt nur mit der von Ihnen angegebenen Generierungsnummer ab.

  1. Rufen Sie ein Zugriffstoken für die Autorisierung aus dem OAuth 2.0 Playground ab. Konfigurieren Sie den Playground so, dass Ihre eigenen OAuth-Anmeldedaten verwendet werden. Eine Anleitung finden Sie unter API-Authentifizierung.
  2. Verwenden Sie cURL, um die JSON API mit einer GET-Objektanfrage aufzurufen:

      curl \
      'https://storage.googleapis.com/storage/v1/b/BUCKET_NAME/o/OBJECT_NAME?ifGenerationMatch=GENERATION' \
      --header 'Authorization: Bearer OAUTH2_TOKEN' \
      --header 'Accept: application/json' \
      --compressed
    

    Dabei gilt:

    • BUCKET_NAME ist der Name des Buckets, in dem sich das Objekt befindet. Beispiel: my-bucket
    • OBJECT_NAME ist der Name des Objekts, für das Sie Informationen abrufen. Beispiel: dog.png
    • OAUTH2_TOKEN ist das Zugriffstoken, das Sie in Schritt 1 generiert haben.
    • GENERATION ist die Generierungsnummer des Objekts, für das Sie Informationen abrufen. Beispiel: 1122334455667788.

      Wenn kein Objekt gefunden wird, das mit der angegebenen Vorbedingung, in diesem Fall also der Generierungsnummer, übereinstimmt, enthält der Antworttext folgende Fehlermeldung:

      "message": "Precondition Failed"

ifMetagenerationNotMatch

In dieser Anfrage wird die Vorbedingung ifMetagenerationNotMatch verwendet. Bei diesem Abfrageparameter ist die Anfrage nur erfolgreich, wenn die Meta-Generierungsnummer eines Objekts von der in der Vorbedingung angegebenen abweicht. Mit diesem Parameter können Sie eine bestimmte Version des Objekts aus der Abfrage ausschließen:

  1. Rufen Sie ein Zugriffstoken für die Autorisierung aus dem OAuth 2.0 Playground ab. Konfigurieren Sie den Playground so, dass Ihre eigenen OAuth-Anmeldedaten verwendet werden. Eine Anleitung finden Sie unter API-Authentifizierung.
  2. Verwenden Sie cURL, um die JSON API mit einer GET-Objektanfrage aufzurufen:

      curl \
      'https://storage.googleapis.com/storage/v1/b/BUCKET_NAME/o/OBJECT_NAME?ifMetagenerationNotMatch=METAGENERATION' \
      --header 'Authorization: Bearer OAUTH2_TOKEN' \
      --header 'Accept: application/json' \
      --compressed
    

    Dabei gilt:

    • BUCKET_NAME ist der Name des Buckets, in dem sich das Objekt befindet. Beispiel: my-bucket
    • OBJECT_NAME ist der Name des Objekts, für das Sie Informationen abrufen. Beispiel: dog.png
    • OAUTH2_TOKEN ist das Zugriffstoken, das Sie in Schritt 1 generiert haben.
    • METAGENERATION ist die Meta-Generierungsnummer für ein Objekt. Wenn das angegebene Cloud Storage-Objekt diese Meta-Generierungsnummer hat, schlägt die Anfrage fehl. Beispiel: 5.

      Wenn die angegebene Meta-Generierungsnummer mit der Meta-Generierungsnummer des angegebenen Cloud Storage-Objekts übereinstimmt, wird eine 304-Antwort zurückgegeben.

Beschränkungen

Die Vorbedingungen mit Generierungs- und Meta-Generierungsnummern sind für ACL-Vorgänge nicht zulässig. 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.

HTTP 1.1-ETags

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.

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.

Beispiele für Race-Bedingungen

Im folgenden Abschnitt lesen Sie, welche Race-Bedingungen Sie möglicherweise berücksichtigen müssen.

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 diese Race-Bedingung verhindern, 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 der Kollege 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.

Beispiel: 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. 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

Damit die oben beschriebene Situation nicht eintritt, rufen Sie zuerst die Metadaten von file.txt ab, um deren aktuelle Generierung zu ermitteln. Senden Sie dann die Löschanfrage mit einer if-generation-match-Vorbedingung, die die Generierungsnummer verwendet. Mit der Vorbedingung wird gewährleistet, 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, mit dem Antwortcode 412 Precondition Failed fehl.

Ähnliche Netzwerkunterbrechungen können auch nach der Löschanfrage 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 von 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, als 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.