🗂️

Google Cloud Storage の階層型名前空間(フォルダ)が一般提供されました

2024/11/08に公開

こんにちは、クラウドエース株式会社 第一開発部の阿部です。
これまでは SRE 部に所属していましたが、当社の組織改編により所属部署が変わりました。今後ともよろしくお願いします。

さて、本記事では 2024 年 10 月 15 日に一般提供された Google Cloud Storage の階層型名前空間(フォルダ)について紹介します。

概要

Google Cloud Storage (以降、GCS) とは、 Google Cloud のオブジェクトストレージサービスです。
GCS は、非構造化データのオブジェクト(例えば画像データや動画データのファイル)の保存や、データベースのバックアップ、アーカイブデータの保存などに利用されます。

これまでの GCS のフォルダの取り扱いについて

階層型名前空間の機能が提供される以前は、GCS のバケットはフラットな名前空間でオブジェクトを管理していました。
これは、一般的なファイルシステムがフォルダを持つのに対して、GCS はフォルダを持たないということです。
例えば、 gs://my-bucket/my-folder/my-object というパスでオブジェクトを保存しても、my-folder はフォルダではなく、単にオブジェクト名の一部として扱われていました。

そのような中、2024 年 10 月 15 日に一般提供された階層型名前空間を有効化することで、一般的なファイルシステムのフォルダを作成することができるようになりました。

階層型名前空間の利点

階層型名前空間を有効化することで、以下のような利点があります。

フォルダ管理の一貫性と性能向上

これまで、gcsfuse で GCS バケットをマウントしてファイルシステムとして利用する場合、 ls コマンドなどでファイルが正しく表示されないことがありました。
これは、GCS がフォルダを持たないため、 ls コマンドでファイル・フォルダリストの取得処理をエミュレートする際に階層構造を取得できなかったためです。

そのため、gcsfuse でフォルダを持たない GCS のバケットをファイルシステムとして利用する際には、シミュレートされたフォルダを利用することが一般的でした。
シミュレートされたフォルダとは、/ で終端する名前の 0 バイトオブジェクトをツール上でフォルダのように扱う方法です。
この方法は gcsfuse のみを使用する場合であれば問題なく利用できますが、シミュレートされたフォルダを扱わない他ツールと併用するケースでは、フォルダの扱いが異なるために問題が発生することがありました。

gcsfuse でシミュレートされたフォルダを使用しない場合は --implicit-dirs オプションを指定することで、フォルダが存在するように見せかけることができます。
しかし、このオプションは毎回全オブジェクトのリストを取得する処理を行うため、パフォーマンスが低下する可能性があります。

2024 年 4 月 3 日にマネージドフォルダが提供され、オブジェクトとは異なる管理リソースとしてのフォルダが使用できるようになりました。
しかし、マネージドフォルダは最大 10 階層まで作成可能であり、深い階層を持つフォルダを作成することができませんでした。
gcsfuse もマネージドフォルダに対応していますが、 --implicit-dirs オプションを併用する必要があり、やはりパフォーマンス低下が懸念されます。

階層型名前空間を有効化することで、フォルダを正式に扱うことができるようになり、フォルダ管理の一貫性が向上します。
また、 gcsfuse のようなファイルシステムとして GCS バケットを扱うツールでフォルダを正しく扱うことができるため、パフォーマンス向上が期待できます。

オブジェクトの管理が容易になる

階層型名前空間のフォルダの利点の一つとして、フォルダのリネームが容易になったことが挙げられます。
これまではオブジェクトがフラットな名前空間で管理されていたため、オブジェクトに含まれるフォルダ要素をリネームしたい場合、全てのオブジェクトに対して別名コピー&削除が発生していました。

階層型名前空間を有効にした GCS バケットでは、フォルダをリネームすると、そのフォルダに含まれるオブジェクトも再帰的に変更されます。
また、フォルダ配下のオブジェクトのリネームはアトミックに処理されるため、リネームが中途半端に完了することはありません。
正常に完了した場合は全てのオブジェクトに反映され、エラーになった場合は元の名前に復元されます。
階層型名前空間のフォルダの名前変更はメタデータのみのオペレーションであるため、従来のバケットと比較してオブジェクトのコピー&削除のオペレーションが不要となります。GCS バケットはオペレーションでの費用が発生するため、コスト削減にもつながります。

階層型名前空間の制限事項

階層型名前空間を有効化すると、以下の機能が利用できなくなります。

  • Autoclass
  • きめ細やかなオブジェクトアクセス制御 (ACL)
  • オブジェクトバージョニング
  • オブジェクトの保持ロック
  • バケットロック

なお、「削除(復元可能)」(Soft delete) はプレビュー時において制限されていましたが、現時点では使用可能です。
そのため、今後のアップデートにより制限解除される可能性があります。

また、現時点では、階層型名前空間は GCS のバケット新規作成時にのみ有効化できます。
既存のバケットに対して有効化することはできません。

料金の違い

階層型名前空間を有効化した GCS バケットは、オペレーション料金において、従来のフラットな名前空間の GCS バケットと料金が異なります。

単一リージョンにあるバケットにおけるオペレーション料金は以下の通りです。
(1000 オペレーションあたりの料金です。)

ストレージクラス クラス A (フラットな名前空間) クラス B (フラットな名前空間) クラス A (階層型名前空間) クラス B (階層型名前空間)
Standard $0.0050 $0.0004 $0.0065 $0.0005
Nearline $0.0100 $0.0010 $0.0130 $0.0013
Coldline $0.0200 $0.0100 $0.0260 $0.0130
Archive $0.0500 $0.0500 $0.0650 $0.0650

また、デュアルリージョン、および、マルチリージョン構成のバケットにおけるオペレーション料金は以下の通りです。

ストレージクラス クラス A (フラットな名前空間) クラス B (フラットな名前空間) クラス A (階層型名前空間) クラス B (階層型名前空間)
Standard $0.0100 $0.0004 $0.0130 $0.0005
Nearline $0.0200 $0.0010 $0.0260 $0.0013
Coldline $0.0400 $0.0100 $0.0520 $0.0130
Archive $0.1000 $0.0500 $0.1300 $0.0650

詳細は Cloud Storage のオペレーション料金のページをご確認ください。
また、掲載している情報は 2024 年 11 月時点の情報のため、最新の情報は公式ドキュメントをご確認ください。

各フォルダの違いのまとめ

シミュレートされたフォルダ マネージドフォルダ 階層型名前空間(フォルダ)
実体 オブジェクト マネージドフォルダ リソース フォルダ リソース
階層の深さ 無制限 ※1 最大 10 階層 最大 50 階層
IAM ポリシーの適用
gcsfuse 対応 ✅ ※2

※1 パス名の合計長さが 1024 バイトを超える場合はエラーとなる
※2 --implicit-dirs オプションを使用する必要がある

階層型名前空間を有効化した GCS バケットの作成方法

階層型名前空間を有効化した GCS バケットの作成方法について説明します。
なお、制限事項のセクションでも説明した通り、既存のバケットに対して階層型名前空間を有効化できません。

Cloud コンソールによる作成方法

GCS バケットの新規作成画面でバケット名入力ボックスの下にある「データ量が多いワークロード向けにストレージを最適化」をクリックします。
「このバケットで階層的な名前空間を有効にする」のチェックボックスが表示されます。このチェックボックスを有効にすると、階層型名前空間が有効になります。

image
「このバケットで階層的な名前空間を有効にする」のチェックボックス

その他は、 GCS バケット作成の手順と変わりありません。

コマンドラインによる作成方法

コマンドラインで作成する際は、 gcloud storage buckets create コマンドに --enable-hierarchical-namespace オプションを追加します。
下記は、バケット作成に必要な最低限のオプションを付与したものです。

gcloud storage buckets create gs://BUCKET_NAME --location=BUCKET_LOCATION \
  --uniform-bucket-level-access --enable-hierarchical-namespace

注意事項として、 --enable-hierarchical-namespace オプションを使用する際は、必ず --uniform-bucket-level-access オプションもあわせて使用する必要があることです。
--uniform-bucket-level-access オプションを付与せずに階層型名前空間の GCS バケットの作成コマンドを実行した場合は以下のようなエラーで作成に失敗します。

ERROR: (gcloud.storage.buckets.create) HTTPError 400: Hierarchical namespace buckets must use uniform bucket-level access.

Terraform による作成方法

Terraform Google Provider (バージョン 6.9.0) で、階層型名前空間のバケット作成に対応しています。
例として、以下のような設定で作成が可能です。

resource "google_storage_bucket" "sample" {
  name          = "my-bucket"
  location      = "us-central1"
  storage_class = "STANDARD"

  # 階層型名前空間の有効化に必要な設定
  uniform_bucket_level_access = true

  # 新設定
  hierarchical_namespace {
    enabled = true
  }
}

階層型名前空間のフォルダ作成方法

階層型名前空間を有効にした GCS バケットでは、オブジェクトを作成する際に、オブジェクト名に / が入っていると自動的にフォルダが作成されます。
例えば、 gs://my-bucket/my-folder/my-doc.txt というパスでオブジェクトを保存すると、my-folder というフォルダが作成されます。

image
オブジェクトアップロード時の動作イメージ

オブジェクト名に複数の / が入っている場合は、再帰的にフォルダが作成されます。

また、オブジェクト作成とは別に、フォルダを作成することも可能です。
コマンドラインで以下のように実行します。

gcloud storage folders create gs://BUCKET_NAME/FOLDER_NAME

オブジェクトアップロード時と異なるのは、FOLDER_NAME にスラッシュが含まれていても、再帰的にフォルダは作成されないという点です。
例えば、 gs://my-bucket/my-folder/child-folder というパスでフォルダを作成したい場合、先に gs://my-bucket/my-folder というパスでフォルダを作成しておく必要があります。

なお、 gcsfuse の場合、前述のフォルダ作成は自動的に行われません。これは、 gcsfuse が一般的な UNIX ファイルシステムの動作を模倣しているためだと思います。
gcsfuse でマウントしたフォルダ [1] にファイルを作成する場合は先にファイル保存先のフォルダを作成しておく必要があります。(mkdir コマンドなど)

階層型名前空間のフォルダのリネーム・削除方法

階層型名前空間のフォルダのリネームや削除の操作はこれまでの GCS バケットにおけるオブジェクトの操作と変わりありません。

gcsfuse でマウントしたフォルダであれば、通常のファイルシステムと同様に mv コマンドでリネーム可能です。

mv /path/to/before-rename /path/to/after-rename

階層型名前空間の有無による性能の変化

階層型名前空間を有効にしたバケットでは、 Hadoop ベースの処理、ファイル志向のワークロード処理、AI および ML 処理において性能が向上すると説明されています。(参考ドキュメント)
このうち、ファイル志向のワークロード処理として、gcsfuse でマウントした GCS バケットに対して簡易的なベンチマークを実施しました。
条件は以下の通りです。

  • 計測は以下の 3 つの GCS バケットに対して実施
    • A パターン: 階層型名前空間を有効化
    • B パターン: 階層型名前空間を無効、かつ、シミュレートされたフォルダを使用
    • C パターン: 階層型名前空間を無効、かつ、 --implicit-dirs オプションを使用
    • ※B パターンと C パターンは、 gcsfuse の引数に --rename-dir-limit 65536 を付与し、同時リネーム上限を設定
  • 約 48000 ファイルを 3 階層のフォルダに GCS バケットに分散配置
  • find コマンド と mv コマンドの実行時間を計測
  • n2-standard-2 マシンタイプの GCE 上で計測
コマンド A パターン B パターン C パターン
find コマンド 45.7 秒 36.3 秒 35.6 秒
mv コマンド 12.2 秒 47 分 11 秒 51 分 10 秒

find コマンドを使ったファイル検索処理においては、階層型名前空間を有効にした A パターンが B パターンや C パターンに比べてやや低速になることが分かりました。
この結果は少し驚きましたが、 Optimize performance in buckets with hierarchical namespace enabled のドキュメントに以下のような記載があり、バケット内のオブジェクト全検索のようなパターンの場合はむしろ性能的に不利になるようです。

In buckets with hierarchical namespace enabled, listing all objects for the entire bucket or with a prefix is resource-intensive as the operation must traverse each folder and subfolder, similar to the ls -r command in a file system.

フォルダ配下のオブジェクト数が少ない場合は A、B、C のいずれのパターンでも性能に大きな差はないと思われます。

一方で、 mv コマンドを使ったフォルダのリネーム処理は、階層型名前空間を有効にした A パターンが B パターンや C パターンに比べて圧倒的に高速になることが分かりました。
これは階層型名前空間の GCS バケットではフォルダのリネーム処理がアトミックに処理される一方、従来の GCS バケットではフォルダのリネーム処理は、フォルダ配下の全オブジェクトを作成・削除する処理と同等となるためです。

まとめ

GCS バケットの階層型名前空間(フォルダ)について紹介しました。
階層型名前空間を有効にすることで、以下のような利点があります。

  • gcsfuse と gcloud CLI (または gsutil) の相互運用性が向上する。
  • フォルダのリネーム処理がアトミックに処理され、性能と信頼性が向上し、オペレーションコストが削減される。

一方で、階層型名前空間を有効にすることで、以下のようなデメリットがあります。

  • オブジェクト全検索のような一部のユースケースでは性能が低下する可能性がある。
  • オブジェクトバージョニングや Autoclass 、オブジェクトの保持ロックといった一部の機能に制限がある。

そのため、階層型名前空間を有効にする際は、ユースケースに適しているかを検討することが重要です。

この記事が GCS を利用する際の参考になれば幸いです。

脚注
  1. Linux などの UNIX 系 OS ではディレクトリと表記するべきだが、当ブログ記事ではフォルダ表記で統一する ↩︎

Discussion