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

我觀察到,客戶端機器從單一伺服器使用 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.xz 138 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.xz 414KiB/s
3. 國外伺服器單連接下載: 2.26 MB/s

補充:文件是下載到內存的(tmpfs),因此避開了並發磁碟 I/O 帶來的影響。


簡短版本:

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

具體來說:

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

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

這是一個TCP連接的發送窗口。

綠色部分為發送者已發送,且接收者已確認(ACKed)。
黃色部分為發送者已發送,但接收者尚未確認("in-flight")。
藍色部分為可用但尚未發送。
灰色部分為不可用。

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

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

剛開始的時候傳輸速率應該是指數被增長的,直到丟包發生。丟包會有兩種情況:
1.當接收者發送給發送者的ACK丟失了,這時會觸發超時(timeout)。
2.當發送者發送給接收者的數據包丟失了,發送者會收到接收者發來的重複ACK,如果發送者收到了3個重複的ACK,也會認為發生了丟包。

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

好,那麼現在我們來看多TCP連接的擁塞控制。
我們假設有兩條同樣的TCP連接。在他們的連接中間有一個共用的瓶頸路由器,帶寬為R。

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

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

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

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

references:

  • James F. Kurose, Keith W. Ross: Computer Networking: A Top-Down Approach, 6e

1、2樓的回答都對,問題的關鍵,其實是在路由器上。

在不存在鏈路爭用的情況下,單連接可以做到和多連接一樣快。
例如,我這裡區域網用的是百兆交換機,下載文件到內存,可以達到11.3MB/s:

百兆的理論速率是12.5MB/s(100Mbps),考慮到幀間隔、不同包長等因素,這個速率比較接近理論速率了。在此情況下,「多連接比單連接下載快」並不成立,或者說,只有很小的性能提升。

推而廣之,假設你的PC和http://python.org的伺服器之間的所有交換設備(路由器、防火牆、交換機等),都只為你的這個下載提供服務,等價於你獨佔這整個傳輸通道的全部帶寬,此時,單連接下載也不會比多連接下載慢多少。

問題是,這些中間設備,通常服務於成千上百(萬)的用戶,帶寬是供所有的用戶共享使用的。路由器的帶寬有限,無法保證每個連接都按照它所能支持的最大速率進行傳輸,即便不考慮路由器本身做的流量控制功能,單單這成百上千(萬)的用戶訪問所形成的TCP連接之間的競爭,就會產生如1樓所說的,各連接均分整個帶寬的情況。
因此,現實環境下,由於傳輸網路的帶寬有限,通常各個連接會均分帶寬,導致單連接下載時速率較低,而多連接下載時速率較高。


手機怒答,簡單的說,就是tcp的擁塞避免機制完全不適用於現有的網路條件了。
設計tcp的年代,網路帶寬很低,所以tcp被設計成一個極度友好的協議,一旦發現擁塞就拚命退讓,但是現在的網路已經帶寬極大改善了,而網路質量反而極大降低,延遲也大了很多(滑動窗口在大延遲下成了一個很逗比的存在),所以當tcp進行擁塞避免的時候,其實網路根本就沒有擁塞,只是質量不好丟了點包而已。結果就是tcp沒有辦法最大化的利用帶寬。


為了確保可靠傳輸,tcp一次最大只能傳輸一個window size的數據,在收到這些數據的ack之後才會進行下一次的數據傳輸,這是tcp的基本工作原理。

tcp header里給windows size只預留了16位,造成了早期的tcp實現最大windows size都只有64k,而如果在一個rtt為250ms的網路環境里進行數據傳輸,只有在收到這64k數據的ack之後才能進行下一個64k的數據傳輸,所以單個session最大的傳輸速率 = window size / rtt 也就是64kb/0.25s=256kbps 。

在rtt小的區域網環境里這個數值會更大一些,但總體而言單個tcp 連接的傳輸速率總是受限的,為了實現更大的傳輸速率,最簡單的辦法也就是使用多連接了

當然,通過設置更大的windows size或降低網路環境的latency 也可以提高單個tcp連接的傳輸速率


從我個人的經驗,"單連接下載,速度沒有達到客戶端網路的最大帶寬"的原因有二:
1. 伺服器端對單個連接的最大帶寬做了限制,或者伺服器達到IO上限無法按客戶最大帶寬提供數據。
2. 客戶到伺服器端的鏈路不穩定,如果出現丟包的話就極大影響速度,每一次丟包就相當於踩了一腳剎車。

如果上述兩個條件都不存在的話,單連接下載,是完全可以達到最大帶寬的。


一樓說的有道理,不過個人看法更同意二樓(王丹)的解釋。
鹵煮說的情況,與一樓的包級別粒度的分析似乎略偏,這個問題似乎是流級別的。
二樓我不知理解對不對,簡單說,就是:
「一條TCP流在沿途遭遇了瓶頸設備,拖慢了整條TCP速率,以至於用戶端的帶寬占不滿;
多條TCP流的多路傳輸匯聚起來,使總體流量瓶頸拉到了用戶接入端的地方。
故在用戶看起來,多條TCP佔滿了自己的全部接入帶寬。」


不管因為什麼也不能說出 "傳輸層不應該影響網路層" 這樣的話吧
樓上各位已經解釋的差不多了,基本是tcp 流量控制的問題。
全面的話應該還要考慮到路由,擁塞控制,網路波動等。
中午了,該吃飯了。


因為有些路由器或垃圾運營商限制會話數量


推薦閱讀:

為什麼區域網的IP普遍是192.168開頭?

TAG:計算機網路 | TCP |