応用読了目安 15 分#アップロード#署名付きURL#ストリーム#検証#タイムアウト
ファイルのアップロード — サーバーを通すか、通さないか
動画の投稿を許したら、アプリのメモリが枯れて全機能が落ちた。1人が 800MB を送っただけだった。受け取り方を決める前に、どこを通すかを決める。
この記事の進み方
What — 経路は2つある
ファイルをどこに置くかは同じでも、どこを通すかで性質がまったく変わります。
アプリがファイルを受け取り、検証してから保存先へ送る。
ブラウザ ──▶ アプリ ──▶ S3
│
└ 検証・変換ができる- 検証のしやすさ
- やりやすい
- サーバーの負荷
- 全部通る
- 大きいファイル
- 苦しい
- 実装の単純さ
- 単純
- –中身を見てから保存できる。ウイルス検査や変換を挟みやすい。
- –帯域もメモリもアプリが負担する。冒頭の事故はここ。
- –ロードバランサやプロキシのタイムアウト・サイズ上限にも引っかかる。
小さいファイルならサーバー経由で十分。大きくなるほど、直接アップロードの利点が効いてくる。
- 署名付き URL
- 一定時間だけ有効な、特定の操作を許す URL。これを持つ人だけが保存先へ書ける。
- マルチパートアップロード
- 大きなファイルを分割して送る仕組み。途中から再開できる。
- ストリーム処理
- 全体をメモリに載せず、流れてくるぶんだけ順に扱うこと。
- 孤児ファイル
- 保存先には存在するが、アプリ側の記録と結びついていないファイル。
- Content-Type
- ファイルの種類を示す申告。ブラウザや利用者が自由に指定できるので、信用できない。
境目はおおむね「数十 MB」
どちらを選ぶかの目安です。
| ファイルの大きさ | 経路 |
|---|---|
| 〜数 MB(画像、PDF) | サーバー経由で十分 |
| 数十 MB〜(音声、資料) | どちらでも。サーバーの規模次第 |
| 数百 MB〜(動画) | 直接アップロード一択 |
上限を「1GB」と決めた時点で、サーバー経由という選択肢は消えていました。 冒頭の事故は、上限だけ決めて経路を決め直さなかったことが原因です。
Why — サーバーを通すと、通り道のすべてが制約になる
途中の箱にも上限がある
ブラウザからアプリまでの間には、いくつもの箱があります。
- 1ブラウザ
- 2CDN / ロードバランサ
- 3アプリ
- 4保存先
1/4
ブラウザ — 大きなファイルでもメモリに全部載せずに送れる。ここは問題になりにくい
どれか1つでも引っかかれば失敗する。そしてエラーの出方が箱ごとに違うので、原因が分かりにくい。
箱ごとに独立した設定があり、片方だけ直しても通りません(network/load-balancer と同じ構造)。
メモリは「同時に何人が上げているか」で決まる
1人 800MB でメモリが枯れたのは、丸ごと読んでいたからです。
ストリームで流せば、一度に持つのは数 MB のバッファだけになります。しかし同時アップロード数が増えれば、それでも積み上がります。
1人あたり 8MB のバッファ × 同時 200 人 = 1.6GB
「1人ぶんが軽い」は「全体が軽い」ではありません。
直接アップロードには、直接アップロードの穴がある
サーバーを通さない代わりに、アプリが中身を知らないまま保存が完了します。
- 申告された種類と、実際の中身が違う
- 完了を通知せず、ファイルだけ残る(孤児ファイル)
- 上限を超えたファイルが置かれる
署名付き URL は「置いてよい」という許可であって、「何を置いてよいか」を細かく縛るものではありません。条件を付けられる範囲は保存先の仕組みに依存します。
演習 — まず自分で判断する
確認 — ここまで読めたか
上限 1GB の動画アップロードを実装します。経路はどちらを選びますか?
確認 — ここまで読めたか
サーバー経由のアップロードで、メモリ不足を避けるには何をしますか?
読み終わりましたか?
読了にすると、これを前提とする記事がロードマップで開放されます。