過去の自分に読ませたかった
안녕하신게라!パナソニック コネクト株式会社クラウドソリューション部の加賀です。
実は昔、「とりあえずs3fsでマウントしてあれば良いよ」と言われそのまま本番に持ち込んだ結果、バッチ処理が二重起動してデータが壊れたことがあります。原因は flock が動作しないこと。「そりゃS3はオブジェクトストレージなんだからロックなんてないよ」と言われればそれまでですが、当時はその解像度がなく、ファイル利用用途まで踏み込まずにハマりました。
そんな折、「S3をNFSマウントできる上にPOSIX互換」という触れ込みのAmazon S3 Files(東京リージョン2026年4月GA)を色々調べたら、思った以上にスゴかったのでまとめます。
内部的にはEFS技術を基盤としたhigh-performance storage(以下HPS)を挟み、NFSv4.1/4.2でPOSIX互換のファイルアクセスセマンティクスを提供するもので、s3fsやgoofys、Mountpoint for Amazon S3とは設計思想が根本的に違います。
本記事は、前半で「なぜPOSIXが大事なのか」を整理した上で、FUSE系ツールとの設計上の違いを解説します。後半はS3 Filesの挙動と制約、ユースケース別の選定指針です。
FUSE系 vs S3 Files 比較
| 観点 | FUSE系ツール(s3fs / goofys / Mountpoint for Amazon S3) | Amazon S3 Files |
|---|---|---|
| アーキテクチャ | FUSEでファイル操作をS3 APIに直接変換 | HPS経由でS3にアクセス |
| プロトコル | FUSE(ユーザランド) | NFSv4.1/4.2(カーネル空間) |
| POSIX互換性 | 部分的。ロック不可。renameはs3fs/goofysで非アトミック(COPY+DELETE)、Mountpoint for S3は非対応 | POSIX互換(ハードリンク・mandatory lockは非対応) |
| 整合性 | S3のstrong consistency(2020年12月〜)に依存 | NFS内は強い整合性(read-after-write consistency)。NFS→S3エクスポートは書き込み非活動後、最大60秒で反映 |
| 読み取り特性 | S3 API経由のみ | 小ファイルは低レイテンシ、1 MiB以上のread操作はS3直接ストリーミング |
| 料金モデル | S3料金のみ | S3料金 + HPS料金 + ファイルシステム操作料金 |
| Lambda連携 | マウント不可 | マウント可(ただしVPC Lambda必須) |
POSIXの何が嬉しいのか?
POSIX(Portable Operating System Interface)が策定された背景には、1980年代のUnix乱立問題があります。AT&T系、BSD系、各ベンダ独自のUnix派生が増え、同じ「ファイルを開く」操作でもOSごとに微妙に挙動が違う。ある環境で動いたプログラムが別の環境では壊れる。なかなか難儀な移植性の問題を解決するためにIEEEが標準化したのがPOSIXです。
POSIX準拠のファイルシステムでは、ファイルロック(flock/fcntl)による排他制御、アトミックなrenameによるクラッシュセーフな書き込み、パーミッション(chmod/chown)によるアクセス制御が保証されます。これらが「共通で当たり前に動く」ことの最大のメリットは、アプリケーション開発者がストレージの実体を意識しなくて済む点です。裏側がローカルディスクだろうがNFSだろうがEFSだろうが、open() → write() → close() のコードは変わりません。
S3 Filesはこの恩恵を活かすサービスです。ストレージの実体はS3なのに、アプリから見れば普通のファイルシステムとして振る舞う。既存のコードを1行も変えずにS3の上で動かせる。それがPOSIXの強みです。
ただし「互換」であって「準拠」ではない点には注意が必要です。S3 Filesはハードリンクやmandatory lockなど、一部のPOSIX機能をサポートしていません。大半のアプリケーションはそのまま動きますが、これらの機能を利用しているソフトウェアでは検証が必要です。
逆に、s3fsのようにPOSIX非準拠の環境では、開発者がオブジェクトストレージの制約を常に意識しなければなりません。「この操作はS3で安全か?」「ロックは効くか?」「renameは壊れないか?」を自分で判断する必要があります。会社の共有フォルダでExcelを開いたとき「○○さんが編集中です。読み取り専用で開きますか?」と表示されたことがあると思いますが、あれがまさにファイルロックです。s3fsにはこの仕組みがないため、2人が同時に保存すれば後勝ちでデータが静かに消えます。
排他制御(ファイルロック)
flock -n /mnt/efs/app.lock -c "./start_daemon.sh"
ほとんどのデーモンやバッチ処理は flock() や fcntl() でロックファイルを作り、二重起動を防止しています。s3fsではこのロックが動作しないため、複数インスタンスでデーモンが同時起動し、データ競合やファイル破損が起こります。
アトミック操作なrename
多くのアプリケーションは「安全な書き込み」を write-then-rename パターンで実装しています。
with open("/mnt/efs/data.tmp", "w") as f:
f.write(new_content)
f.flush()
os.fsync(f.fileno())
os.rename("/mnt/efs/data.tmp", "/mnt/efs/data.json") # アトミック!
POSIXでは rename() はアトミックです。途中で電源が落ちても「古いファイル」か「新しいファイル」のどちらかが必ず残ります。中途半端な状態にはなりません。s3fsでは rename = COPY + DELETE なので、COPY後DELETE前にクラッシュすれば2つのファイルが残り、COPY中に他プロセスが読み取れば不整合なデータを参照する可能性があります。操作が非アトミックであること自体がリスクです。
実際に動かないソフトウェアが出てくる
| ソフトウェア | 必要なPOSIX機能 |
|---|---|
| SQLite | ファイルロック(全モード。特にWALモードではshm共有メモリも必要) |
| WordPress(NFS共有時) | flock、rename |
| Git(共有リポジトリ) | アトミックrename(--localクローン時はハードリンクも利用) |
| rsync | symlink、chmod(--link-dest使用時はハードリンクも利用) |
「検証環境では動いたのに本番で壊れた」の典型パターンです。アクセスの少ない検証環境では偶然うまく動いていただけであり、同時アクセスが増えると容易に破綻します。
アーキテクチャの違い
S3はファイルシステムじゃない
S3(Simple Storage Service)はオブジェクトストレージです。図書館の書庫をイメージしてください。本(ファイル)を収める(PUT)、取り出す(GET)、蔵書一覧を見る(LIST)ことはできますが、書庫の中で本の内容を途中だけ書き直すことはできません。
s3fsやgoofys、そしてMountpoint for Amazon S3は、この書庫の前に立ち読みスペースを置くようなツールです。S3のAPI(PutObject、GetObject)をFUSE経由でPOSIXの open()/read()/write() に変換しています。ls を打てばListObjects APIが走り(遅い)、mv を打てばCopyObject + DeleteObjectが走り(壊れうる)、flock を打てど何も起こりません(ロックしない)。
問題の本質は、S3にはファイルシステムの根幹となる概念が存在しないことです。アトミックrenameがない(COPY + DELETEの2操作)。ファイルロックがない。ハードリンクもない。ディレクトリのアトミック操作もない(「プレフィックス」に過ぎない)。
AWS公式のMountpoint for S3ですら、ランダムライト不可、ファイルロック非対応で、POSIX準拠を目指していない旨を公式ドキュメントに明記しています。AWS公式が本気で作ってもPOSIX準拠にできないのが「S3マウント」の限界です。ツールの問題ではなく、S3というオブジェクトストレージの構造的限界です。
S3 Files「書庫の横に閲覧席を作ってみた」
S3 Filesの実体を一言で言えば「S3をSource of Truthとし、EFS技術を基盤としたHPS(アクティブデータを保持する高速ストレージ層)を挟んだ構成」です(公式ドキュメントでは「Built using Amazon EFS」と表現されています)。
s3fsが書庫の棚の上で無理やり作業するようなものだとすれば、S3 Filesは書庫の隣にちゃんとした閲覧席を設けて、必要な本だけ取り寄せて手元で作業できるようにした構成です。よく使う本は閲覧席に置きっぱなしにでき(HPS)、しばらく触らなかった本は自動で書庫に戻されます(デフォルト30日)。分厚い辞典は閲覧席に出さなくても書庫で直接読めます(1 MiB以上のreadはS3から直接ストリーミング)。
NFS(Network File System)は1984年にSun Microsystemsが開発したファイル共有プロトコルで、LinuxやmacOSには標準で組み込まれています。マウント後はローカルのフォルダと全く同じように使えます。
# S3 FilesをNFSでマウント(mount helperを使用する場合。TLS暗号化が有効になる)
sudo mount -t efs -o tls \
fs-0123456789abcdef0 \
/mnt/efs
# mount helperを使わない場合(TLS暗号化なし。検証用途向け)
sudo mount -t nfs4 -o nfsvers=4.1 \
fs-0123456789abcdef0.efs.ap-northeast-1.amazonaws.com:/ \
/mnt/efs
NFSクライアントから見ると、flock() / fcntl() によるファイルロックが正常動作し、rename() はファイルシステム上では即時完了(POSIX準拠)で、UID/GID/パーミッション(chmod, chown)が動作し、シンボリックリンクにも対応しています。
ただしハードリンクは非対応です(公式のUnsupported featuresに明記)。各ファイルが1つのS3オブジェクトキーに対応する設計上、複数パスから同一inodeを参照するハードリンクは実現できません。また、ロックはすべてadvisory lockであり、mandatory lockingには対応していません。つまりロックの取得・確認はアプリケーション側の責任であり、ロックを無視してファイルにアクセスすること自体はカーネルによって阻止されません。
結局どこが違うのか
ここまでの話を整理すると、FUSE系とS3 Filesの差はアプローチそのものです。
FUSE系は、S3のAPIをファイル操作に翻訳する「通訳」です。通訳である以上、S3側に存在しない概念(ロック、アトミックrename)は訳しようがありません。どれだけ優秀な通訳でも、原文にない言葉は出てこない。
S3 Filesは、S3とは別にPOSIX互換のファイルシステム(HPS)を持っていて、そこにデータを同期する構成です。ファイルシステム操作(ロック、rename、パーミッション等)はこのHPS上で完結するので、普通に動きます。S3は「永続保存先」として後ろに控えているだけです。
FUSE系はアプリとS3の間に通訳を挟んでいるだけなので、S3の制約がそのまま透けて見えます。S3 Filesはアプリとの間に本物のファイルシステムがあるので、POSIX互換の操作がそのまま動く。この構造の違いが、冒頭で挙げたロック・rename・パーミッションの対応差になります。
知っておくべき挙動と制約
次に、実際に触ってみて気になった挙動や制約についてです。
ここまで持ち上げておいて言うのもなんですが、S3 Filesは万能ではありません。使い所を考える必要があります。
料金体系とコスト特性
S3 Filesの料金体系はEFS Standardとは異なる独自のものです(最新の単価はS3 Files Pricingを参照)。大きく3つの課金軸があります。
| 課金軸 | 内容 |
|---|---|
| S3ストレージ | Source of Truthとしてのオブジェクト保管(通常のS3料金) |
| HPS | ファイルシステム上に保持されたアクティブデータ量に応じた課金 |
| ファイルシステム操作 | 読み書き操作(最小32 KiB単位)+ メタデータ操作(最小4 KiB単位) |
いいね!と思ったポイントは「全データがHPSに載るわけではない」ことです。1 MiB以上の読み取りはS3から直接ストリーミングされるためファイルシステム操作料金が発生しません。また、アクセスされなくなったデータは設定期間(デフォルト30日)後に自動的にHPSから退避されます。大容量データをPOSIXで扱いたいがEFSに全量置くとコストが爆発してしまう、というケースにこそS3 Filesは有効です。実質的に「ホットデータだけ高速ストレージに載り、コールドデータはS3の安価なストレージに留まる」自動階層化が働くためです。
最小課金サイズに注意。HPSの最小保存サイズは10 KiB、各read/write操作の最小課金サイズは32 KiBなので、1 KiBのファイルを100万個書き込むと、ストレージ課金は実データ約1 GiBに対して10 GiB分、I/O課金は約32 GiB分に膨らみます。S3側でも「リクエスト数 × 単価」の課金があるため、小ファイルの大量処理はコスト効率が悪い。AWS公式のベストプラクティスでも「1 MiB以上の大きなIOサイズを使うことで、per-operationオーバーヘッドを償却できコスト効率が良い」と推奨されています。
S3バケットにS3 Versioningの有効化が必須なので、変更のたびに旧バージョンが保存されます。ライフサイクルルールで非最新バージョンを定期削除する運用を検討しましょう。
少額とはいえ見落としがちなのがCross-AZのデータ転送コストです。S3 FilesのマウントはDNS名で行い、DNSが同一AZのマウントターゲットIPへ自動解決してくれるため、利用する全AZでマウントターゲットを作っていれば問題は起きません。転送コストが発生するパターンは、あるAZでマウントターゲットを作り忘れた場合、そのAZのインスタンスは別AZのマウントターゲットへ接続するため、AZ間転送料金(各方向$0.01/GB)が静かに積み上がります。公式でも「コンピューティングリソースが動く各AZにマウントターゲットを作る」ことを推奨しています。
NFS↔S3の同期とlost+found
ファイルシステムとS3バケット間の同期には方向ごとに異なる特性があります。
NFS → S3(エクスポート)方向では、ファイルへの書き込みが非活動になると、S3 Filesは最大60秒以内に変更をS3バケットへエクスポートします。この間に発生した連続する変更は1回のS3 PUTリクエストにまとめられます(公式ドキュメント)。ログファイルに50回appendしても1回のS3 PUTで済むバッチ処理です。裏を返せば、NFS側で書き込んだデータがS3バケットに反映されるまでには最大60秒の遅延があるため、S3 API経由で即座に読み取りたいワークロードでは注意が必要です。
S3 → NFS(インポート)方向では、別のアプリケーションがS3 APIでオブジェクトを追加・変更・削除すると、S3 FilesがS3 Event Notifications経由で検知し、HPSに載っているデータを自動更新します。ただし、HPSから期限切れで退避済みのファイルは、次にアクセスされるまで更新されません。
NFS同士の操作は即時反映です。同期遅延が問題になるのは「S3 API ↔ NFS」のプロトコル境界を跨ぐときだけで、NFS内で完結する限り通常のファイルシステムと同じ強い整合性(read-after-write consistency)が得られます。
典型的な罠として、S3イベント通知でLambdaを起動し、そのLambda内でNFSマウント経由でファイルを読もうとするケースがあります。S3 APIとNFSを混在利用する設計では、同期タイミングを意識したアーキテクチャが必要です。AWS公式のベストプラクティスでも「S3 APIとファイルシステムのどちらかをprimary writerに指定する」ことが推奨されています。
また、NFS側とS3 API側で同一ファイルを同時に変更してコンフリクトが発生した場合、S3バケットがSource of Truthとして優先され、NFS側の変更はファイルシステムのルートにある.s3files-lost+found-<file-system-id>ディレクトリに退避されます。lost+foundに移動されたファイルは自動では削除されず、ストレージコストにも計上されるため、定期的な確認・削除が必要です。
ディレクトリrenameの落とし穴
ファイル単位のrename()と同様に、ディレクトリのrename/moveもファイルシステム上では即時完了します。ただしバックグラウンドでは、S3側で全オブジェクトのCOPY+DELETEが必要になるため、数百万ファイルを含むディレクトリの場合はS3同期に数時間かかる場合があります。同期完了までの間、S3バケット上には旧・新両方のプレフィックスが一時的に存在します。S3リクエストコストもオブジェクト数に比例して発生します(公式では約1,200万オブジェクトを警告閾値としており、--AcceptBucketWarningで回避可能)。ファイルシステムのスコープを最小限のプレフィックスに絞ることが、公式ベストプラクティスでも推奨されています。
読み取りパスの二層構造
S3 Filesの読み取りは、ファイルサイズと読み取りサイズによって経路が変わります。
まずインポート閾値(デフォルト128 KiB未満、変更可)より小さいファイルは、ディレクトリへの初回アクセス時にメタデータごとHPSへ自動インポートされます。以降はサブミリ秒〜1桁ミリ秒で読めます。
一方、1回のread操作が1 MiB以上になると、HPSにデータがあってもS3バケットから直接ストリーミングされます。S3のほうがスループットに優れるため、大きな読み取りではこちらが効率的です。
機械学習のモデルファイル、画像・動画のバッチ処理、科学計算の中間ファイルのように1ファイルが大きく、シーケンシャルに読むワークロードがS3 Filesの最も輝く場面です。設定ファイルやメタデータ参照のような小さいファイルの読み書きもHPSの低レイテンシで快適に捌けますが、数KiBのファイルを数百万個単位で扱うようなケースでは最小課金サイズのためコスト効率が悪化します。そういった大量の小ファイルI/OにはElastiCacheやDynamoDBのほうが向いています。
ネットワーク設計とセキュリティ
LambdaでS3 Filesを使う場合、LambdaをVPC内に配置する必要があります。これはマウントターゲットがVPC内のENI経由でしかアクセスできないためです。VPC Lambdaになることで、NAT Gatewayなしではインターネットアクセスできない、サブネットのIPアドレス枯渇に注意が必要、セキュリティグループの設計が必須、といった制約が加わります。つまり「LambdaでS3 Filesを使う=ネットワーク設計が必要」ということです。手軽さと引き換えに、POSIX互換のファイルシステムが得られます。
S3 Filesは転送中のデータをTLSで、保存時のデータをAWS KMSキーで暗号化します(デフォルトはAWS所有キー、カスタマーマネージドキーも指定可能)。なお、TLS暗号化を有効にするにはmount helper(efs-utils)経由でマウントする必要があります。NFSアクセスにはマウントターゲットのセキュリティグループでNFSポート(2049/TCP)を許可する必要があります。EC2・Lambda問わず、セキュリティグループの設計は必須です。
NFSv4のKerberosベースセキュリティには非対応です。エンタープライズ環境でNFS認証にKerberosを前提としている場合は設計の見直しが必要になります。
既存バケットに被せる前に
NFS経由でファイルを変更すると元のS3オブジェクトに設定されていたS3 ACLとカスタムユーザー定義メタデータが消えます(Unsupported S3 featuresに明記)。既存のS3データでACLやカスタムメタデータに依存している場合は、S3 Filesを被せる前に影響を確認しておかないと泣きます。
S3キー名にも注意が必要です。S3はオブジェクトキーをただの文字列として扱うので、foo/./bar や foo/../bar、空パスコンポーネント(foo//bar)、nullバイトを含むキーも普通に作れます。しかしPOSIXでは . はカレントディレクトリ、.. は親ディレクトリとしてカーネルが予約しているため、これらのキーはファイルパスとして解釈できません。S3 FilesはPOSIX互換だからこそ、こうしたPOSIX非互換なキー名のオブジェクトにはアクセスできない仕様になっています。既存バケットにS3 Filesを被せる場合は、対象キーにこれらのパターンが含まれていないか事前に確認しておきましょう。
運用のポイント
S3 Filesは同期の健全性をCloudWatchメトリクスで公開しています。特に見ておきたいのは PendingExports(まだS3に書き戻せていない変更の数)と ExportFailures(書き戻しに失敗した数)の2つ。PendingExports が右肩上がりならワークロードが同期レートを超えているサインだし、ExportFailures が1でも立ったらパーミッションかKMSキーの問題を疑ったほうがいい。アラーム設定は公式ベストプラクティスでも推奨されているので、デプロイ時にセットで入れておきましょう。
地味に怖いのがEventBridgeルールの扱いです。S3 Filesは DO-NOT-DELETE-S3-Files というプレフィックスのEventBridgeルールを自動作成して、S3バケット側の変更を検知しています。名前からして「消すなよ」と全力で主張しているわけですが、TerraformやCloudFormationでEventBridgeルールを一括管理していると、うっかり巻き込んで消してしまうことがあり得ます。もし消えるとS3側の変更がファイルシステムに反映されなくなるので、IaCのスコープから除外しておくと良いでしょう。
だいたいは超えませんが、クォータも把握しておきましょう。最大ファイルサイズ48 TiB、ディレクトリ深度の上限1,000階層、S3オブジェクトキー長の上限1,024バイト、1ファイルあたりのロック数上限512(全インスタンス合計)あたりは設計に響くので、詳細は公式のQuotasを一読しておくと安心です。
ユースケース別の選定指針
| ユースケース | 推奨 | 理由 |
|---|---|---|
| 静的ファイルの配信 | S3 + CloudFront | NFSマウント不要。S3に置いてCDNで配るだけ |
| 大量データのシーケンシャル読み取り(POSIX不要) | Mountpoint for S3 | AWS公式、高スループット。POSIX非準拠 |
| 複数EC2でのPOSIX共有ワークスペース(S3連携不要) | EFS | S3同期のオーバーヘッドなし。NFS完結で構成がシンプル |
| 複数EC2でのPOSIX共有ワークスペース(S3連携あり) | S3 Files | POSIX互換、同時アクセス安全、S3の耐久性とコスト効率を両立 |
| S3 APIとNFSの両方からアクセス | S3 Files | 同期特性を理解した上で使う |
| HPC・大規模MLでS3連携が必要 | Amazon FSx for Lustre | データリポジトリ連携でS3と自動同期。高スループット |
| LambdaでS3のファイルを参照(POSIX不要) | S3 API(boto3等) | VPC不要でシンプル |
| LambdaでS3のファイルを参照(POSIX必要) | S3 Files + VPC Lambda | flock等が必要なら選択肢はこれ。VPC設計が前提になる |
| 小さいファイルを大量に捌きたい | ElastiCache / DynamoDB | ファイル操作のコスト割高 |
| 「とりあえず」S3をマウントしたい(検証用途) | s3fs / goofys | 本番非推奨、あくまで検証用途 |
おわりに
冒頭で書いた「s3fsでflockが動かなくてデータが壊れた」事故は、S3 Filesがあの時点で存在していれば防げていました。もちろんS3 Filesも万能ではなく、同期タイミングの癖や小ファイル大量処理のコスト非効率、ハードリンク非対応といった制約はあります。でも少なくとも「POSIXが必要なのにs3fsでごまかしごまかし妥協する」という選択をしなくて良い時代となりました。
「S3をマウントしたい」と言われたとき、まず確認すべきは「POSIXが必要か?」「ファイルサイズは?」「S3 APIとの併用はあるか?」の3点です。条件が合えばS3 Files、シーケンシャル読み取り専用ならMountpoint、検証だけならs3fs。この判断ができるだけで設計の質が変わることでしょう。
過去の自分に読ませたかった。誰かの未来に役立ちますように。
お断り
記事内容は個人の見解であり、所属組織の立場や戦略・意見を代表するものではありません。
あくまでエンジニアとしての経験や考えを発信していますので、ご了承ください。