第 2 章 アップロード経路: チャンク分割、並列処理、再開 (重要)
アップロード側の目標は、変動するネットワークの下でも「帯域を使い切る」状態に可能な限り近づけつつ、失敗によるコストを最小限 (失敗したチャンクだけを再送) に抑えることです。 この 2 つの目標を合わせることで、アップロードが速く感じられる理由の大部分を説明できます。
2.1 チャンク分割
- クライアントは、ファイルを複数のチャンクに分割しなければなりません (MUST)。チャンクは、アップロードと再試行の最小単位です。
- 並列処理のスケジューリングと状態の表現を単純にするため、チャンクは固定サイズ (またはファイルごとにサイズを決める方針) とすべきです (SHOULD)。
- すぐに得られる利点: 失敗が起きても、影響を受けるのはファイル全体ではなく 1 つのチャンクだけです。
2.2 並列アップロード
並列処理の目的は「スレッドを増やすこと」ではありません。現実のネットワークで単一接続が抱える、次の 3 つの制約を避けることです。
- スロースタートとウィンドウの拡大: 単一の接続は立ち上がりが遅く、特にリージョンをまたぐ RTT が大きい場合に顕著です。
- 回線のジッター: 1 本の接続でジッターが起きると、全体の速度が落ちることがあります。並列処理によってその影響が平準化されます。
- フローごとのシェーピング: 単一のフローを絞り込むネットワークもあります。複数のフローを使うと、(コンプライアンス上の制約の範囲内で) 帯域の上限に近づける場合があります。
- クライアントは、同時実行数を制限して (たとえば 4~12) 使うべきです (SHOULD)。性能の低いデバイスでは、メモリの急増を避けるために同時実行数を下げます。
- クライアントは、同時実行数を適応的に調整してもかまいません (MAY)。スループットが上がれば増やし、エラー率が上がれば減らします。
2.3 冪等性と再試行
- 同じチャンクを繰り返しアップロードしても冪等でなければなりません (MUST)。重複して送信されても、すでに完了した状態を壊してはなりません。
- サーバーは、(transferId, fileId, chunkIndex) またはそれと同等の制約で一意性を保証すべきです (SHOULD)。
- クライアントは、指数バックオフによる再試行を実装しなければなりません (MUST)。失敗時は、失敗したチャンクだけを再試行すべきです (SHOULD)。
2.4 再開できるアップロード
- サーバーは、クライアントが完了済みのチャンクを飛ばせるように、「どのチャンクがすでにアップロードされているか」に答えられなければなりません (MUST)。
- チャンク数に比例して状態のサイズが増えるのを避けるため、アップロード済みの集合は、ビットマップや範囲の集合として表現すべきです (SHOULD)。
- 速度面の利点: ネットワークの中断、ブラウザーのクラッシュ、ネットワークの切り替えのあとでも、再開すれば 0% からやり直しにはなりません。
2.5 「アップロードしながら共有」 (任意)
- システムは、納品のワークフローを加速するために、アップロードの進行中でも、利用できる転送 ID と共有リンクを発行してもかまいません (MAY)。
- アップロードの完了前に共有を許可する場合は、受信者に何が見えるのかを明示しなければなりません (MUST)。たとえば、未完了のコンテンツはまだダウンロードできない、あるいは進捗だけが表示される、といった内容です。