コンテンツへスキップ
HexaTransfer
ブログへ戻る
技術詳解

チャンクベースのアップロードアーキテクチャ設計ガイド

チャンク化戦略、再開可能アップロード、並列転送最適化など、堅牢なチャンクベースのアップロードシステムの設計方法を解説します。

チャンクベースのアップロードアーキテクチャは、ファイルを固定サイズまたは可変サイズの断片に分割して個別に送信するため、ネットワークの一時的な障害があっても10GBのファイルをゼロから再送することにならない。2つの主要なオープン標準はAWS S3 Multipart Upload(最小パートサイズ5MB、最大10,000パート)とtus.ioの再開可能プロトコル(広く実装されているRFCドラフト)だ。正しく設計されたチャンクアップロードは、高レイテンシのリンクで5〜10倍の高スループットを実現し、短い切断にも耐え、受信側での並列復号を可能にする。

なぜモノリシックアップロードは大規模では失敗するのか

5GBのファイルのHTTP PUTを1回実行するだけで、6通りの失敗方法にぶつかる。TCPの輻輳ウィンドウは高レイテンシのパスでは帯域幅の上限を大きく下回るまでに長い時間がかかる。ブラウザはオリジンごとに同時接続を6に制限しており、大部分の帯域幅が未使用のままになる。サーバーサイドのリクエストタイムアウト(nginxはデフォルト60秒、CloudFrontは非ストリーミングで30秒)が長い時間のアップロードを強制終了する。モバイルネットワークが基地局を切り替えるたびに接続が数分ごとに切れる。そして1ビットが破損しても全体の転送を再開する必要がある。チャンクアップロードはこれらすべてを、作業単位を小さく、独立した再試行が可能で、並列処理に適した形にすることで解決する。

チャンクサイズの選び方

チャンクサイズはトレードオフだ。小さいチャンクは障害からの回復が速く、細かい進捗粒度を提供するが、HTTPのオーバーヘッドが増える。大きいチャンクはハンドシェイクとTLSのコストを分散させるが、チャンクが失敗して再送が必要な場合に帯域幅が無駄になる。典型的な範囲:モバイルの低品質ネットワークアップロードには1MB〜5MB、デスクトップウェブアップロードには5MB〜16MB、信頼できるリンク上のサーバー間転送には16MB〜64MB、1TBのファイルで10,000パートの上限を強制されるS3 Multipartには100MB以上。接続が安定してきたらサイズを拡大する動的適応システムもある。

固定サイズ対コンテンツ定義チャンク化

固定サイズのチャンク化(例えば8MB単位)は実装が簡単で並列処理に適し、正確な再開オフセットをサポートする。rsyncやresticで使われるコンテンツ定義チャンク化は、Rabin指紋のようなローリングハッシュに基づいて境界を選ぶため、ファイルの中間への挿入が後続のチャンク境界すべてをずらさない。CDCはバックアップツールの重複排除には優れているが、純粋なファイル転送では複雑さとCPUコストが報われない。アップロードアーキテクチャでは固定サイズがシンプルで、S3マルチパートのパートやtus.ioのオフセットにクリーンにマッピングできる。

再開可能アップロードプロトコル

tus.ioプロトコルは、Go実装のtusd、tus-js-client、Uppy、多くのサーバーフレームワークで実装され、チャンクを追記するためにUpload-Offsetヘッダーを持つHTTP PATCHを使う。HEADリクエストでサーバーの現在オフセットが返るため、クライアントはネットワーク中断後にどこから再開するか分かる。S3 Multipart Uploadは異なるモデルを使う。UploadIdを取得するためにアップロードを開始し、各パートをアップロードし(1始まりのインデックス)、ETagのリストでCompleteMultipartUploadを送る。両プロトコルはクライアントの再起動後も状態を維持し、接続の切断から正常に回復する。

並列アップロードの並行性

チャンクを並列でアップロードすると、高レイテンシのリンクでスループットが劇的に向上する。HTTP/1.1はブラウザでオリジンごとに6並列接続が上限。HTTP/2は単一接続上で多くのストリームを多重化するが、フロー制御ウィンドウの制約は残る。典型的なアップロードスケジューラはチャンクをキューに入れ、4〜8並列でディスパッチし、サーバーが429や503を返したときにバックプレッシャーをかける。並行性が高すぎるとISPのシェーピングやミドルボックスの接続制限を引き起こし、少なすぎると帯域幅を使い切れない。経験的には、家庭用ブロードバンドで4並列ストリーム、ギガビット光回線で8〜16が多くのワークロードに最適だ。

クライアントサイドの状態と再開メタデータ

再開可能アップロードにはブラウザがクラッシュしたりノートPCがシャットダウンした後に再開するのに十分な状態をクライアントが記憶する必要がある。Web Storageの一部であるIndexedDBは、ファイルのハッシュ、チャンク数、どのチャンクが成功したかを含むアップロードマニフェストを保存する。ファイルのSHA-256ハッシュでマニフェストをキー付けすることで、同じファイルを再追加したときに中断したところから再開できる。7日以上経過した古いマニフェストは肥大化を防ぐために削除する。モバイルでは、WKWebView(iOS)とChrome Custom Tabs(Android)がメモリ不足でIndexedDBを削除することがあるため、可能であれば重要な状態をネイティブストレージに永続化する。

サーバーサイドのチャンク処理

サーバーはチャンクを完全なファイルに再組み立てするか、S3 Multipartの場合はS3に再組み立てを委ねる必要がある。最小限のアーキテクチャ:各チャンクのPATCHを受け入れ、アップロードIDとチャンクインデックスをキーにした一時ブロブに書き込み、RedisかPostgreSQLのメタデータストアにオフセットを記録し、CompletePartで組み立て完了とマークする。ロードバランサーを使うバックエンドはローカル状態を共有できないため、チャンクブロブにはローカルディスクではなくオブジェクトストレージ(S3、Cloudflare R2、Backblaze B2)を使う。放棄されたアップロードは24〜72時間後にガベージコレクションしてストレージを回収する。

チャンクごとおよびエンドツーエンドの整合性確認

アップロード時に各チャンクをハッシュで検証する。S3 MultipartのETagはパートごとのMD5ハッシュ(またはオブジェクト全体の複合ハッシュ)だ。より強い整合性のために、クライアントサイドでチャンクごとにSHA-256を計算してヘッダーで送信し、サーバーはチャンクの隣にそれを保存して再読み込み時に検証する。全チャンクのアップロード後、再組み立てされたファイルのMerkleツールルートかストリーミングハッシュを計算してクライアントに返す。クライアントは元のファイルの自分のハッシュと比較する。不一致は問題のあるチャンクの再アップロードをトリガーする。

暗号化とチャンク化の相互作用

エンドツーエンド暗号化はチャンク化を少し複雑にする。各チャンクにはAES-GCMでのIV再使用を避けるために固有のノンスが必要で、チャンク境界が認証スキームの一部でなければならない。典型的なアプローチ:ルートファイル暗号化鍵からHKDF-SHA256でチャンクインデックスをコンテキスト情報として使って各チャンクの鍵を導出し、AES-256-GCMとゼロまたはインクリメントするノンスで各チャンクを暗号化する。攻撃者がチャンクを継ぎはぎや並び替えできないように、チャンクインデックスと総チャンク数をAADに含める。復号時には平文を解放する前にすべてのチャンクが存在し順序通りであることを確認する。

本番環境での構成

本番対応のチャンクアップロードシステムは、5MB〜16MBのチャンク、tus.ioまたはS3 Multipartのプロトコル、4〜8の並列ストリーム、IndexedDBバックの再開状態、チャンクごとのSHA-256整合性チェック、そしてオプションの導出鍵によるチャンクごとのE2EEを組み合わせる。HexaTransferはAES-256-GCMによるクライアントサイドのチャンク化暗号化と再開可能アップロードを使い、不安定な接続上でも10GBのファイルを確実に処理する。

https://hexatransfer.com — 無料、アカウント不要、最大10GB。

エンドツーエンド暗号化で大容量ファイルを安全に送信

エンドツーエンド暗号化で最大10GBのファイルを無料で転送。アカウント不要。ファイルはアップロード前にブラウザで暗号化されるため、他の誰にも読まれません。

ファイルを送信