AWS Elemental MediaStoreは「フォルダ」という幻想を見せ続けられるのか

AWS Elemental MediaStoreのフォルダはAmazon S3のように幻なのでしょうか。一般的なファイルシステムと同様のフォルダではありませんが、オブジェクトストレージにおけるフォルダを実現しているのではないかと思います。
2021.07.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

清水です。数あるDevelopersIOブログの中でも、私の好きなエントリのひとつに以下の記事があります。

AWSのオブジェクトストレージサービスであるAmazon S3において、マネジメントコンソールなどで確認できるフォルダは幻想で、実態は単純なKey-Value型ストレージでしかない、ということを解説した名作です。Amazon S3を使用する上では必読のエントリかと思います。もし未読の方は、ぜひ一度上記エントリを読んでみましょう。私はクラスメソッド入社前に熟読していました *1

さて、AWSでS3とよく似たストレージサービスにAWS Elemental MediaStoreというものがあります。S3をものすごくシンプルに「HTTPベースでファイルをアップロード、ダウンロードできるファイルストレージサービス」と考えれば、MediaStoreもほぼ同等の機能を持っていると言えます。またMediaStoreはメディア向けに最適化したストレージということで、ファイルサイズの上限が25MB *2であることやレイテンシの低さ、リリース当時の2017年の段階ではS3でカバーできていなかった即時一貫性(immediate consistency)をそなえていることが特徴です *3

このMediaStore、マネジメントコンソールなどからは「フォルダ」というものが見えます。ユーザガイドにも「フォルダ」についての記載があります。ですが、内部的なストレージとしてはS3を使用していることが「よくある質問」などに記載されています。

AWS Elemental MediaStore に書き込まれるコンテンツには、どの程度の耐久性がありますか?

AWS Elemental MediaStore に取り込まれたオブジェクトは、複製されたライトバックキャッシュに送信されます。そのライトバックキャッシュによって、オブジェクトは書き込み直後に Amazon S3 によってバックアップされているストレージに移されます。オブジェクトは通常、Amazon S3 にすぐに移されますが、この処理が遅れるか、まったく実行されない場合があります。ワークロードに迅速な耐久性が必要な場合は、Amazon S3 を直接使用することをお勧めします。

よくある質問 - AWS Elemental MediaStore | AWS

冒頭に示したブログのとおり、S3において「フォルダ」は幻です。ということはMediaStoreにおける「フォルダ」も幻なのでしょうか、本エントリではこのMediaStoreにおける「フォルダ」について確認してみました。

Amazon S3の「フォルダ」という幻を再確認する

まずはS3の「フォルダ」についてのおさらいです。といっても基本的には冒頭に挙げたエントリを熟読しましょう。まとめてみると以下になるかなと思います。(といっても私の解釈になっているので、正確な解釈は繰り返しになりますが上記エントリを参照ください。)

  • S3はKey-Value型データストアなのでフォルダという概念はない
  • オブジェクトを一覧表示するAPIのパラメタによって、特定のフォルダ直下の要素のみをリストアップする挙動が可能
  • マネジメントコンソールではこの仕組みを利用してフォルダという幻を見せている

個人的にはAPIパラメタ(s3api list-objects--prefix--delimiter)で任意の文字列をフォルダとみなし、その直下の要素のみをリストアップする挙動がすごくおもしろいなと思っています。そして一般的にS3で「フォルダ」としてオブジェクトをグルーピングする際には区切り文字として/が利用されますが、工夫して(もちろんマネジメントコンソールでの操作はできませんが)異なる区切り文字でフォルダを表現できないかなぁ、などと妄想したものです。個人的にはフォルダ(ディレクトリ)の区切り文字(パス)は>が好きです。歴史的にはMulticsで使用されていたようで *4、学生時代にふと読んだ書籍に記載されていて知りました *5。例えばMacのFinderなどでも階層表示方法としてパスバーの部分で使われていますね。この>を使った階層構造がS3で実現できないかなぁ、というぐあいです。(実際は>がS3のオブジェクト名で「使用しない方がよい文字」となっていることもあり、難しそうですが。 *6

AWS Elemental MediaStoreの「フォルダ」について確認する

さて本題のMediaStoreの「フォルダ」についてです。まずはユーザガイドを確認してみます。おもいっきり「フォルダ」というセクションがありますね。

マネジメントコンソールからファイル(オブジェクト)をアップロードして挙動を確認してみましょう。Target pathでフォルダ名fooを入力、アップロードするファイルbar.txtを選択します。このbar.txtには文字列barが格納されているとします。(以降、本エントリでは同様にファイル名.txtにはファイル名が文字列として入っているとします。)

アップロード操作後です。コンテナ直下にフォルダfooがあります。Type:Folderも確認できますね。

そのフォルダの配下にオブジェクトが存在しています。

AWS CLIでも確認してみましょう。mediastore-dataコマンドを使用します *7。(mediastoreコマンドはコンテナ操作用です *8 *9。)

--pathオプションを付与せず、コンテナ直下を確認してみます。フォルダがありますね、"Type": "FOLDER"の情報もあります。

% aws mediastore-data list-items \
    --endpoint https://xxxxxxxxxxxxxx.data.mediastore.ap-northeast-1.amazonaws.com
{
    "Items": [
        {
            "Name": "foo",
            "Type": "FOLDER"
        }
    ]
}

このフォルダfooに対してdescribe-objectget-objectなどの操作をしようとしてもエラーとなってしまいます。エラー内容はObject Not Foundということで、まさにオブジェクトは存在しない、という状況となります。(念のためfoofoo/の2パターン試してみましたが、同じ結果でした。)

% aws mediastore-data describe-object \
    --endpoint https://xxxxxxxxxxxxxx.data.mediastore.ap-northeast-1.amazonaws.com \
    --path foo      
An error occurred (ObjectNotFoundException) when calling the DescribeObject operation:

今度は--pathでフォルダ名を指定してみます。フォルダ内のオブジェクト情報が取得できる、というぐあいですね。

% aws mediastore-data list-items \
    --endpoint https://xxxxxxxxxxxxxx.data.mediastore.ap-northeast-1.amazonaws.com \
    --path foo
{
    "Items": [
        {
            "Name": "bar.txt",
            "Type": "OBJECT",
            "ETag": "57f0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "LastModified": "2021-07-07T19:21:30.629000+09:00",
            "ContentType": "text/plain",
            "ContentLength": 4
        }
    ]
}

もう少し具体的な例として、フォルダ内にさらにフォルダ、その配下に複数ファイルを持つ構造としてみます。

% aws mediastore-data list-items \
    --endpoint https://xxxxxxxxxxxxxx.data.mediastore.ap-northeast-1.amazonaws.com \
    --path foo/
{
    "Items": [
        {
            "Name": "quux",
            "Type": "FOLDER"
        },
        {
            "Name": "bar.txt",
            "Type": "OBJECT",
            "ETag": "57f0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "LastModified": "2021-07-07T19:21:30.629000+09:00",
            "ContentType": "text/plain",
            "ContentLength": 4
        }
    ]
}

% aws mediastore-data list-items \
    --endpoint https://xxxxxxxxxxxxxx.data.mediastore.ap-northeast-1.amazonaws.com \
    --path foo/quux/
{
    "Items": [
        {
            "Name": "garply.txt",
            "Type": "OBJECT",
            "ETag": "0672xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "LastModified": "2021-07-07T20:58:22.300000+09:00",
            "ContentType": "text/plain",
            "ContentLength": 7
        },
        {
            "Name": "corge.txt",
            "Type": "OBJECT",
            "ETag": "34a4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "LastModified": "2021-07-07T20:58:04.316000+09:00",
            "ContentType": "text/plain",
            "ContentLength": 6
        },
        {
            "Name": "grault.txt",
            "Type": "OBJECT",
            "ETag": "8818xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "LastModified": "2021-07-07T20:58:13.125000+09:00",
            "ContentType": "text/plain",
            "ContentLength": 7
        }
    ]
}

うん、なかなか「フォルダ」っぽいですね。

MediaStoreの「フォルダ」をもっと調べてみる

mediastore-data list-itemsコマンドに--pathオプションでフォルダを指定すると、そのフォルダ配下のファイルならびにフォルダの情報が取得できます。またlist-itemsコマンド実行時には--pathオプションで指定したフォルダ階層以上の情報は得られません。s3api list-objectsコマンドで言えば、--prefix--delimiterで細かに制御されている状態と同等かと思います。非常に「フォルダ」っぽい挙動です。反対に、フォルダを無視した一覧表示を得るAPI(S3で言えばs3api list-object--prefix--delimiterなしの実行)は用意されていません。ということは、MediaStoreには「フォルダ」は存在するとみて良いのでしょうか。もう少し深追いしてみましょう。

ユーザガイドで詳細を確認してみると、いくつか気になる点がでてきます。まずひとつ目は「フォルダ」だけの作成ができません。マネジメントコンソールでもそのような操作項目はなく、AWS CLIやAPIでもcreate-folderみたいなものはありません。フォルダが作成できるのは、あくまで最初のフォルダ配下のオブジェクトをアップロードしたときのみ、となります。

続いて2つ目の注意点です。「フォルダ」だけを残すことはできません。フォルダ内の最後のオブジェクトを削除すると、フォルダも消えてしまいます。以下、実際に確認してみましょう。コンテナ直下に baz/waldo.txtというオブジェクトをアップロードしました。フォルダbazが(配下のオブジェクトとともに)存在していますね。

% aws mediastore-data list-items \
    --endpoint https://xxxxxxxxxxxxxx.data.mediastore.ap-northeast-1.amazonaws.com
{
    "Items": [
        {
            "Name": "baz",
            "Type": "FOLDER"
        },
        {
            "Name": "foo",
            "Type": "FOLDER"
        }
    ]
}

% aws mediastore-data list-items \
    --endpoint https://xxxxxxxxxxxxxx.data.mediastore.ap-northeast-1.amazonaws.com \
    --path baz/
{
    "Items": [
        {
            "Name": "waldo.txt",
            "Type": "OBJECT",
            "ETag": "9324xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "LastModified": "2021-07-07T21:03:23.965000+09:00",
            "ContentType": "text/plain",
            "ContentLength": 6
        }
    ]
}

このフォルダbazの配下のオブジェクトwaldo.txtを削除します。

% aws mediastore-data delete-object \
    --endpoint https://xxxxxxxxxxxxxx.data.mediastore.ap-northeast-1.amazonaws.com \
    --path baz/waldo.txt

削除後、コンテナ直下を確認してみます。bazフォルダは(明確な削除操作を行なっていないにもかかわらず)なくなっていますね。

% aws mediastore-data list-items \
--endpoint https://xxxxxxxxxxxxxx.data.mediastore.ap-northeast-1.amazonaws.com
{
    "Items": [
        {
            "Name": "foo",
            "Type": "FOLDER"
        }
    ]
}

つまり、「フォルダ」が存在しているのであれば、「フォルダ」配下には必ずオブジェクトが1つ以上は存在している、ということとなります。

この挙動やユーザガイド記載のMediaStoreの「フォルダ」の特徴を踏まえた個人的な考えです。たしかにMediaStoreにはユーザガイドに項目が設けられているように「フォルダ」の考えがあります。しかしそれは通常のファイルシステムにおける「フォルダ」ではなく、オブジェクトストレージにおけるオブジェクト整理(リスト表示など)のための「フォルダ」を実現しているだけ、ではないのでしょうか。

具体的には、通常のファイルシステムでので「フォルダ」は、配下のフォルダ・ファイルシステムのアドレスなどを所有し、実際に階層化するものかと思います。このため例えば、フォルダの名称変更や、フォルダの移動といったことが可能です。対して、MediaStoreで実現しているオブジェクトストレージの整理のための「フォルダ」は、あくまでリスト表示などをした際にその「フォルダ」のみの情報を見せる、といった使い方に限定されているかと思います。ユーザガイドに記載があるようにMediaStoreでは「フォルダ」の名称の変更はできません。また「フォルダ」の移動もできません。MediaStoreでの「フォルダ」は(通常のファイルシステムの「フォルダ」が持つ)配下のフォルダ、オブジェクトのアドレスなどの情報は持っていないと考えられます。

また冒頭でも述べたとおり、MediaStoreのバックエンドはS3であるという情報が公開されています。そしてあくまでS3がKey-Value型ストレージであるということを考えると、S3をラップしている部分(ある意味これがMediaStore本体と言えるかもしれません)が上手に「フォルダ」という幻想を見せているのかな、と思いました。例えばlist-itemsのAPIを投げた際には、MediaStoreの内部的にはS3に対してlist-objects--prefix--delimiterを指定したAPIを実行して処理している、というような挙動なのかなと想像しています。

ただし、S3よりもより高レベルなところで「フォルダ」を見せているのかなとも思います。例えばMediaStoreのAPIではフォルダ内の一覧表示のみサポートしており、S3のようにバケット(=コンテナ)配下のすべてのオブジェクトの一覧表示を行ったり、パラメタで区切り文字などを指定する、という形式ではありません。ここはもしかしたら、S3開発時の設計思想 *10ではフォルダのような考えでも区切り文字(パス)も指定できるべきと考えていた、対してMediaStoreについては用途もある程度限定されること、またオブジェクトストレージにおいてもフォルダの考え(少なくともリスト表示の際のフォルダの利用)がより必要になっていることなどから、/を区切り文字としあらかじめてフォルダを仮想的に実現しているのではないかな、などと思いました。

まとめ

メディア向けに最適化されたストレージサービスであるAWS Elemental MediaStoreの「フォルダ」について確認してみました。MediaStoreには「フォルダ」という概念・考えがありますが、通常のファイルシステムのそれとは違います。バックエンドがAmazon S3であるということもありますが、S3よりも高レベルなところで「フォルダ」(という幻?)を見せているのかな、というのが私の考えです。メディア向けということで利用用途がある程度は限定されていること、またS3のリリースよりもだいぶ後にリリースされている *11サービスであることから、利便性向上のための「フォルダ」という考えをあらかじめ取り入れているのかなと思いました。

脚注

  1. 入社は2015年、エントリ公開は2014年です。
  2. リリース当初は10MBでした。20MBを経て現在(2021/07)は25MBが上限です。
  3. Amazon S3では2020年12月に強い書き込み後の読み込み整合性(strong read-after-write-consistency)をサポート、結果整合性より強い整合性を利用できるいう意味では即時一貫性と同等であるかと思います。
  4. Path (computing) - Wikipedia
  5. 実はついこの間まで区切り文字は覚えているけど、使われていたOSを忘れてしまっていて、Wikipediaを見ながらやっと思い出すことができました。
  6. オブジェクトキー名の作成 - Amazon Simple Storage Service
  7. AWS Elemental MediaStoreをAWS CLIで操作してみた 〜Object操作系コマンド編〜 | DevelopersIO
  8. AWS Elemental MediaStoreをAWS CLIで操作してみた 〜Container操作系コマンド編〜 | DevelopersIO
  9. AWS Elemental MediaStoreをAWS CLIで操作してみた 〜リリース後に追加されたContainer操作系コマンド編〜 | DevelopersIO
  10. Amazon S3は今年2021年春、サービスリリースから15年を迎えました。(AWS Pi Week 2021 | The Birth of the AWS Cloud)当時は当然マネジメントコンソールなどなく、APIでの操作を前提としていました。
  11. Amazon S3のリリースは2006年、AWS Elemental MediaStoreのリリースは2017年です。