オブジェクトのバージョニングと同時実行制御

概要

バージョニングが有効になっているバケットでは、オブジェクトの非現行バージョンを保持し、誤って削除したデータを元に戻したり、データの古いバージョンを取得したりできます。バケットのバージョニングのオン / オフは、いつでも切り替えることができます。バージョニングをオフにすると、既存のオブジェクト バージョンはそのまま保持され、新しいバージョンがアップロードされるたびにバケットの既存のライブ バージョンが削除されます。

バケットのバージョニングが有効かどうかにかかわらず、各オブジェクトには正の整数フィールドが 2 つあります。

  • 世代。新しいオブジェクトが同じ名前で既存のオブジェクトを置き換えると更新されます。
  • メタ世代。メタデータの世代を表します。このフィールドは 1 から始まり、コンテンツの特定の世代のメタデータ(ACL、Content-Type など)が更新されるたびに更新されます。世代番号が更新されると、リセットされます。

この 2 つはいずれも整数値ですが、バージョニングされたデータを扱う場合には世代のみを使用します。世代とメタ世代は同時実行制御で使用されます(詳細は後で説明します)。

gsutil でオブジェクトのバージョニングを使用する場合、オブジェクトの世代が埋め込まれたストレージ URL を使用できます。この URL をバージョン固有の URL といいます。たとえば、バージョンのないオブジェクトの URL は次のようになります。

gs://bucket/object

このオブジェクトに 2 つのバージョンが存在する場合、バージョン固有の URL は次のようになります。

gs://bucket/object#1360383693690000
gs://bucket/object#1360383802725000

以降のセクションでは、バージョニングと同時実行制御について詳しく説明します。

オブジェクトのバージョニング

バケットのバージョニングを表示したり、有効または無効にしたりするには、'versioning get'、'versioning set' コマンドを使用します。次に例を示します。

gsutil versioning set on gs://bucket

指定したバケットのバージョニングが有効になります。詳細については、gsutil help versioning をご覧ください。

バージョンが有効になっているオブジェクトのすべてのバージョンと世代 / メタ世代の情報を表示するには、gsutil ls -a を使用します。

gsutil ls -a gs://bucket

特定のオブジェクトを使用してバージョン固有の URL を検索することもできます。また、ワイルドカードも使用できます。

gsutil ls -a gs://bucket/object1 gs://bucket/images/*.jpg

オブジェクトのバージョンを追加するたびに世代値が増加します。このため、gsutil ls で特定のオブジェクトのリストを作成した場合、オブジェクトの最新バージョンは常にリストの最後に表示されます。 たとえば、バケットの gs://bucket/object に 3 つのバージョンが存在する場合、次のように表示されます。

gs://bucket/object#1360035307075000
gs://bucket/object#1360101007329000
gs://bucket/object#1360102216114000

gs://bucket/object#1360102216114000 が最新バージョンで、gs://bucket/object#1360035307075000 が使用可能な最も古いバージョンです。

gsutil でバージョンのない URL を指定すると、オブジェクトのライブ バージョンにだけ処理が実行されます。たとえば、次のコマンドを実行します。

gsutil cp gs://bucket/object ./dir

または

gsutil rm gs://bucket/object

* や ** などのワイルドカードを使用しても同じ結果が得られます。これらのコマンドは、一致したオブジェクトのライブ バージョンだけを処理します。たとえば、次のコマンドを実行すると、ライブ バージョンが削除され、バケット内の各オブジェクトに非現行バージョンが作成されます。

gsutil rm gs://bucket/**

特定のオブジェクト バージョンを操作するには、バージョン固有の URL を使用します。たとえば、前述の gsutil ls -a コマンドで次の出力が生成されたとします。

gs://bucket/object#1360035307075000
gs://bucket/object#1360101007329000

この場合、次のコマンドを実行します。

gsutil cp gs://bucket/object#1360035307075000 ./dir

オブジェクトの 2 番目に新しいバージョンが取得されます。

バージョン固有の URL を gsutil cp コマンドのコピー先に指定することはできません。指定すると、エラーが発生します。バージョニングされたオブジェクトに書き込みを行うと、常に新しいバージョンが作成されます。

また、一部のシェルでは「#」が特殊文字として扱われます(例: extendedglob が有効になっている zsh)。「#」を特殊文字として処理するシェルを使用している場合は、次のように引数を引用符で囲む必要があります。

gsutil cp 'gs://bucket/object#1360035307075000' ./dir

オブジェクトが削除されると、gsutil ls の通常の出力には表示されなくなります(-a オプションを指定せずに実行した場合)。削除されたオブジェクトを復元するには、gsutil ls -a を実行して使用可能なバージョンを確認し、バージョン固有の URL の 1 つをバージョンのない URL にコピーします。たとえば、次のコマンドを実行します。

gsutil cp gs://bucket/object#1360101007329000 gs://bucket/object

これを行うと、新しいオブジェクトのバージョンが作成され、追加で課金されます。古いバージョン固有のオブジェクトを削除すると、余分なコピーを削除できます。

gsutil rm gs://bucket/object#1360101007329000

gsutil mv コマンドを実行すると、この 2 つの手順をまとめて行うことができます。

gsutil mv gs://bucket/object#1360101007329000 gs://bucket/object

バージョニングが有効になっているバケットでオブジェクトのライブ バージョンを削除すると、非現行バージョンが保存されます。

gsutil rm gs://bucket/object

オブジェクトのバージョン固有の URL を削除すると、このバージョンが完全に削除されます(ライブ バージョンが存在する場合でも削除されます)。

gsutil rm gs://bucket/object#1360101007329000

オブジェクトのすべてのバージョンを削除するには、gsutil rm -a オプションを使用します。

gsutil rm -a gs://bucket/object

バケット内のオブジェクトのすべてのバージョン(バケット自体も含む)を削除するには、rm -r オプションを使用します(-r には -a オプションも含まれます)。

gsutil rm -r gs://bucket

オブジェクトに作成されるバージョンの数に制限はありません。バージョニングが有効になっているバケットで同じオブジェクトを何度もアップロードできます。不要なバージョンの削除は自身で行う必要があります。

バージョニングされたバケットのコピー

バージョニングされた 2 つのバケット間でデータをコピーできます。次のようなコマンドを実行します。

gsutil cp -r -A gs://bucket1/* gs://bucket2

バージョニングされたバケットを使用してコマンドを実行すると、各オブジェクトのバージョンがコピーされます。オブジェクトをコピーすると新しい世代が割り当てられるため、gs://bucket2 のコピーには別の世代番号が設定されますが、オブジェクトの並べ替え順は変わりません。たとえば、gs://bucket1 に次のオブジェクトがあるとします。

% gsutil ls -la gs://bucket1 10  2013-06-06T02:33:11Z
53  2013-02-02T22:30:57Z  gs://bucket1/file#1359844257574000  metageneration=1
12  2013-02-02T22:30:57Z  gs://bucket1/file#1359844257615000  metageneration=1
97  2013-02-02T22:30:57Z  gs://bucket1/file#1359844257665000  metageneration=1

コピー後の gs://bucket2 は次のようになります。

% gsutil ls -la gs://bucket2
53  2013-06-06T02:33:11Z  gs://bucket2/file#1370485991580000  metageneration=1
12  2013-06-06T02:33:14Z  gs://bucket2/file#1370485994328000  metageneration=1
97  2013-06-06T02:33:17Z  gs://bucket2/file#1370485997376000  metageneration=1

オブジェクトのバージョンは同じ順序になっています(両方のリストともサイズ順に並んでいます)が、世代番号とタイムスタンプは gs://bucket2 のほうが新しくなっています。

同時実行制御

Cloud Storage を使用してアプリケーションを構築している場合は、同時実行制御に注意する必要があります。通常、gsutil はこの目的で使用されませんが、gsutil に関連して同時実行制御を行うスクリプトを作成する場合があります。

たとえば、gsutil を使用してローリング アップデート システムを実装する場合について考えてみましょう。このシステムでは、データの一部を計算してクラウドにアップロードするジョブを定期的に実行します。 このジョブは、前回のジョブで計算されたデータを使用して処理を開始し、新しい値を計算します。このシステムを強化するため、このジョブを複数のマシンで実行します。この場合、2 つのジョブが同時に実行され、オブジェクトが更新される可能性があります。この場合、次のような競合が起きる可能性があります。

  • ジョブ 1 が新しい値を計算する
  • ジョブ 2 が新しい値を計算する
  • ジョブ 2 が新しい値を書き込む
  • ジョブ 1 が新しい値を書き込む

この場合、ジョブ 1 が読み込む値がその時点の最新値ではなく、更新されたオブジェクトの書き込みを行うと、古いデータが書き込まれる可能性があります(アプリケーションによってはデータが壊れる可能性もあります)。

この問題を回避するには、作成されたオブジェクトのバージョン固有の名前を検索し、その URL に含まれる情報を使用して、後続の gsutil cp コマンドに x-goog-if-generation-match ヘッダーを指定します。この操作は 2 つの手順で実行します。まず、アップロード時に gsutil cp -v オプションを使用して、作成されたオブジェクトのバージョン固有の名前を取得します。たとえば、次のコマンドを実行します。

gsutil cp -v file gs://bucket/object

出力は次のようになります。

Created: gs://bucket/object#1360432179236000

このオブジェクトの世代値を後続の gsutil コマンドで使用します。次のコマンドを実行します。

gsutil -h x-goog-if-generation-match:1360432179236000 cp newfile \
    gs://bucket/object

このコマンドは、Cloud Storage に newfile をアップロードするようにリクエストしますが、アップロード時点での newfile の最新世代が指定値と一致しないと、リクエストが失敗します。

使用するコマンドでオブジェクトのメタデータが更新される場合には、オブジェクトの現在のメタ世代を検索する必要があります。この操作を行うには、gsutil ls -a と -l オプションを使用します。たとえば、次のコマンドを実行します。

gsutil ls -l -a gs://bucket/object

出力は次のようになります。

  64  2013-02-12T19:59:13Z  gs://bucket/object#1360699153986000  metageneration=3
1521  2013-02-13T02:04:08Z  gs://bucket/object#1360721048778000  metageneration=2

この情報を使用して、次のコマンドでオブジェクトの古いバージョンの ACL を設定します。データとメタデータが最新バージョンでないと、コマンドは失敗します。

gsutil -h x-goog-if-generation-match:1360699153986000 -h \
  x-goog-if-metageneration-match:3 acl set public-read \
  gs://bucket/object#1360699153986000

これらのヘッダーを追加しないと、既存の ACL が上書きされます。"gsutil acl ch" コマンドの場合、読み取り / 変更 / 書き込みのサイクルを実行して ACL を編集するため、これらのヘッダーが自動的に使用されます。

世代とメタ世代の機能を確認するには、次の操作を行います。まず、オブジェクトをアップロードし、gsutil ls -l -a でオブジェクトのすべてのバージョンと各バージョンのメタ世代のリストを表示します。次にオブジェクトをアップロードして gsutil ls -l -a を再度実行します。ここで、metageneration=1 というオブジェクト バージョンが 2 つ確認できます。次に、ACL を設定して gsutil ls -l -a を実行します。オブジェクトの最新世代が metageneration=2 になります。

詳細情報

バージョニングと前提条件の使用方法については、https://cloud.google.com/storage/docs/object-versioning をご覧ください。