考察: なぜ HTTP (TCP) の並列ダウンロードが有効か

Published: 2023/10/28


巨大な単一ファイル(e.g. .iso)をダウンロードするとき、 wgetcurl を利用するよりも、 aria2caxel を用いてダウンロードすると早くなる、という記事をみかけたりする。

これらの並列ダウンロードのツールは、内容的には HTTP の範囲リクエスト を利用して、対象ファイルをセグメントに分割し、そのセグメントそれぞれを別々の HTTP コネクションでダウンロードする仕組みである、と理解できる。

同じサーバーに対する接続を複数化するだけでスピードアップするのは、よくよく考えれば不思議である気がしたので、調べた内容をここにまとめる。

TCP のウィンドウ制御

TCP は、送信したバイト列が受信側で漏れなく同じ順番で読み出せるようにするために、送信したい内容を IP パケットに分割し、そのパケットを元々の順番で送っていく。

受け取る側は、パケットが順不同で到着することになるため、ある程度のバッファを用意しておいて、そこに到着したパケットの内容をつめておいて、シーケンス番号上で漏れがないことを確かめられたところから順に、 ACK パケットで、どこまでのシーケンス番号を受信できたかを送信側に返信する。 そしてその内容を上位層のアプリケーションに引き渡していく。

すべての TCP パケットには、ウィンドウサイズを表すフィールドがあり、これは、(ACK)パケットを送っている側が、今どれだけの受信用に用意しているバッファがあるか、を表す。 なので、理屈上は、このウィンドウサイズにおさまるぐらいのデータを、送信側は一気に送ってしまっても良いが、ネットワークは帯域幅というものがあり、あまりに一気に送るとパケットロスが発生し、データが相手側に到達しなくなるリスクが高くなるので、少しずつ一度に送るパケット数を増やす、という制御を行う。 これは輻輳制御と呼ばれる。

輻輳制御では、上記(ACK)パケットから読み取れた最新の受信ウィンドウ(rwnd)とは別に、輻輳制御のためのウィンドウというものをデータ送信側は計算する。 いくつかのプロトコルがあるが、基本的にはなるべく多くの、しかしパケットロスが起きないぐらいのウィンドウサイズになるように自動的に調整されるようなアルゴリズムで、この輻輳制御ウィンドウ(cwnd)は決まっていく。

rwnd と cwnd の小さい方までを、データ送信側はとりあえずパケットとして投げていき、暫くたっても ACK が来なければ来ていない部分から再送していく。

https://www.infraexpert.com/study/tcpip10.html

https://www.infraexpert.com/study/tcpip11.html

TCP の理論値: rwnd が常に BDP より大きければ、帯域幅をフル活用できる(かも)

Bandwidth-Delay Product (BDP) は、帯域幅にラウンドトリップの時間をかけ算したもの。 ネットワークの状態によって存在しているはずの、理論的に到達したい輻輳ウィンドウ幅を表す値となる。 rwind が常にこれよりも大きければ、輻輳制御により、最終的に BDP まで cwnd は拡大していく(と嬉しい)。

仮説: 複数コネクションが効く理由

特に、送信側も受信側も、 BDP の数倍分の、ソケットバッファ(カーネルが通信のために持っておくためのバッファ) を保持していて、かつ、諸々の TCP 高速化の手法(特に例えば、ウィンドウスケーリング) を on にしている場合には、帯域幅のぎりぎりまでの速度を出すのは可能にはなりそうではある。

ただし一般的には、クライアント側がサーバー側の設定をいじることはできないので、常に自分にとって最適なサーバーの TCP 設定がなされていることは期待できない。 そのような場合においては、 TCP 接続を増やすことでチューニングされきらない TCP 接続1本あたりのスピードを量でカバーできて、スピードアップがなされている、という仮説が思い付く。 一般的に HTTP での配布は、全世界の平均的なユーザー接続に対してチューニングするものであり、全世界のユーザー(の平均)はそこまで帯域幅は大きくないであろうから、コネクションの量を用意することで、そこまで大きくない帯域にチューニングされたサーバー側の TCP 接続設定を上手く利用できて、ダウンロードが速くなる、という仮説である。

もしくは、ボトルネックがネットワーク部分ではなく、例えばサーバー側のアプリケーションレイヤーにあるような場合に(e.g. ディスクから読み出していてネットワークの帯域に追い付いていない)、 DoS じみたことにはなるが、リクエスト数を増やすことで、遅いサーバーから N 人で手分けしてダウンロードしていた、といったような効果が期待できる場合も、ありえそうではある。

メモ: on Linux

Linux の場合には、次の資料などが参考になりそう。 具体的に cwnd 等を確認する方法等について述べられている。


Tags: tcphttp