為什麼多 TCP 連線分塊下載比單連線下載快

weixin_33860722發表於2017-03-30

客戶端機器從單一伺服器使用 HTTP 下載一個檔案:

1. 單連線下載,速度沒有達到客戶端網路的最大頻寬;

2. 多連線同時下載,傳輸速度有極大的提高,頻寬被佔滿。假設如下前提:

1. 伺服器是單一的,沒有使用提供相同檔案的其它伺服器,也沒有使用同域名的其它伺服器;

2. 伺服器不對單個連線限速。

那麼,是什麼導致多連線下載的速度大為提高呢?換一種說法,是什麼原因導致單一 TCP 連線沒有儘可能地利用頻寬呢?

是因為不同的 TCP 連線使用了不同的鏈路嗎?可是傳輸層不應該影響網路層的吧?

是因為 TCP 本身的特性嗎?那又是怎樣的特性導致了這種結果呢?

測試結果:

1. 單連線下載:wget –header=’Host: python.org’http://82.94.164.162/ftp/python/3.4.0/Python-3.4.0a3.tar.xz138 KB/s

2. 多連線下載:aria2c -k 1M -x 16 -s 16 –header=’Host: python.org’http://82.94.164.162/ftp/python/3.4.0/Python-3.4.0a3.tar.xz414KiB/s

3. 國外伺服器單連線下載: 2.26 MB/s

補充:檔案是下載到記憶體的(tmpfs),因此避開了併發磁碟 I/O 帶來的影響。

=============================================================================

TCP特性使得每個TCP連線可以得到均等的頻寬。在多使用者環境下,一個使用者擁有越多TCP連線,獲得的頻寬越大。

具體來說:

這個涉及到了TCP的擁塞控制。

我們先看一下單TCP連線的擁塞控制。

這是一個TCP連線的傳送視窗。


5423625-f703d92aa2f062fa.png

綠色部分為傳送者已傳送,且接收者已確認(ACKed)。

黃色部分為傳送者已傳送,但接收者尚未確認(”in-flight”)。

藍色部分為可用但尚未傳送。

灰色部分為不可用。

所以在RTT(round-trip time,來回通訊延遲)不變的情況下,cwnd這個變數基本決定傳輸速率。


5423625-c859c638884caf8c.png

傳送者總會試圖找到不丟包情況下的最大速率。按照TCP協議,在傳輸開始之後,每接收到一個確認(ACK)就會把cwnd這個變數增大一倍。所以TCP連線開始之後應該是這個樣子。


5423625-00511024ee1365d1.png

剛開始的時候傳輸速率應該是指數被增長的,直到丟包發生。丟包會有兩種情況:

1.當接收者傳送給傳送者的ACK丟失了,這時會觸發超時(timeout)。

2.當傳送者傳送給接收者的資料包丟失了,傳送者會收到接收者發來的重複ACK,如果傳送者收到了3個重複的ACK,也會認為發生了丟包。

具體對這兩種情況採取的措施略有不同,但粗略來說,變數cwnd會被減半,也就是說傳輸速率減半。然後cwnd會再次增大,直到下次丟包發生。所以忽略最開始,TCP的吞吐量應該是這樣。


5423625-3ca43d4bd940c092.png

好,那麼現在我們來看多TCP連線的擁塞控制。

我們假設有兩條同樣的TCP連線。在他們的連線中間有一個共用的瓶頸路由器,頻寬為R。


5423625-098b874d0cba402e.png

假設這兩條連線都需要傳輸足夠大量的資料,那麼不論他們誰先開始傳輸,最後一定會均分頻寬。


5423625-0c7ca6433cd47bac.png

因為如果總傳輸速率低於R的時候就會不斷增大傳輸速率,某個連線在增大傳輸速率的時候發生丟包就會減半傳輸速率,最後趨於平衡。

所以k條經過同一節點TCP連線會平分頻寬R,每條連線得到頻寬R/k。

正因為如此,不論是以前的net vampire,還是現在的迅雷都採取增加併發連線數的方法來加快下載速度。

相關文章