2012-04-23 70 views
4

我想了解接收器窗口如何影響吞吐量較高延遲連接。TCP接收窗口

我有兩臺機器的簡單客戶端 - 服務器對應用的,相隔甚遠,與兩個250毫秒的等待時間RTT的之間的連接。我跑這個測試與Windows(XP,7)和Linux(Ubuntu的10.x的),有相同的結果,所以爲了簡單起見,我們假設的情況下: 客戶端接收數據:WinXP的臨 服務器發送數據:Win7的臨 同樣,延遲是250mSec RTT。

我跑我的TCP測試在不改變客戶端上的接收緩衝區大小(默認爲8KB),我在電線上看到(使用Wireshark的):

  • 客戶端發送ACKS到服務器和TCP數據包包含RWIN = 65K
  • 服務器發送數據,並報告RWIN = 65K

在跟蹤我看到3-4的分組的突發(具有1460個字節的有效負載)尋找,隨後立即ACK從客戶端機器發送到服務器,然後約250毫秒沒有然後是從服務器到客戶端的新數據包突發。

所以,結論看來,它填補了接收器的窗口,甚至在服務器不發送新數據。爲了做更多的測試,我這次也運行了相同的測試,改變客戶端機器上的接收器緩衝區大小(在Windows上,更改接收器的緩衝區大小最終影響了機器宣傳的RWIN)。我希望在阻塞ACK之前看到大量的數據包......並且至少有更高的吞吐量。

在這種情況下,我設置的recv緩衝區大小100,000,000。從客戶端到服務器的數據包現在有一個RWIN = 99,999,744(很好,這很好),但不幸的是,從服務器發送到客戶端的數據模式仍然是一樣的:短時間爆發,然後等待很長時間。 爲了確認我在網絡上看到的內容,我還測量了從服務器向客戶端發送一大塊數據的時間。我沒有看到使用大型RWIN或使用默認設置的任何更改。

任何人可以幫助我理解爲什麼改變RWIN並沒有真正影響產量?

幾點注意事項: - 服務器作爲快速發送數據的8Kb 塊中可能使用write() - 正如我以前說過,我看到使用Linux以及類似的效果。更改接收緩衝區大小會影響節點使用的RWIN,但吞吐量保持不變。 - 我分析了數百個數據包之後的跟蹤,給予TCP慢啓動機制足夠的時間來放大CWIN大小。


至於建議,我加入金屬線軌跡的一小快照這裏

No.  Time  Source    Destination   Protocol Length Info 
    21 2.005080 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=11681 Win=99999744 Len=0 
    22 2.005109 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=19305 Ack=1 Win=65536 Len=1460 
    23 2.005116 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=20765 Ack=1 Win=65536 Len=1460 
    24 2.005121 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=22225 Ack=1 Win=65536 Len=1460 
    25 2.005128 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  946 21500 > 57353 [PSH, ACK] Seq=23685 Ack=1 Win=65536 Len=892 
    26 2.005154 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=14601 Win=99999744 Len=0 
    27 2.007106 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=16385 Win=99999744 Len=0 
    28 2.007398 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=24577 Ack=1 Win=65536 Len=1460 
    29 2.007401 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=26037 Ack=1 Win=65536 Len=1460 
    30 2.007403 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=27497 Ack=1 Win=65536 Len=1460 
    31 2.007404 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=28957 Ack=1 Win=65536 Len=1460 
    32 2.007406 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=30417 Ack=1 Win=65536 Len=1460 
    33 2.007408 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  946 21500 > 57353 [PSH, ACK] Seq=31877 Ack=1 Win=65536 Len=892 
    34 2.007883 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=19305 Win=99999744 Len=0 
    35 2.257143 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=22225 Win=99999744 Len=0 
    36 2.257160 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=24577 Win=99999744 Len=0 
    37 2.257358 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=32769 Ack=1 Win=65536 Len=1460 
    38 2.257362 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=34229 Ack=1 Win=65536 Len=1460 
    39 2.257364 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=35689 Ack=1 Win=65536 Len=1460 
    40 2.257365 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=37149 Ack=1 Win=65536 Len=1460 

正如你看到的,服務器停在包#33發送數據。

客戶端在舊分組的分組#34發送ACK(seq = 19305,在分組#20上發送,此處未顯示)。 RWIN爲100Mb,我希望服務器不要阻塞一段時間。

20-30個數據包後,服務器端的擁塞窗口應該足夠大,可以發送比我看到的數據包更多的數據包...... 我假設擁塞窗口最終會長到RWIN ......但即使經過數百個數據包之後,模式也是一樣的:數據數據然後被阻塞爲250mSec ...

+0

無論是機器無線?你能打印出在服務器/客戶端發送的數據包和消息中的順序號嗎?客戶端或服務器端可能會有很多噪音導致數據丟失。 – JustinDanielson 2012-04-23 23:44:20

回答

7

我可以從你提供的樣品猜測兩件事情:

  1. 服務器具有大約15K的發送緩衝區。
  2. 您提供的轉儲是在服務器端完成的。

對於TCP連接的窗口縮放到一定的大小,發送方的發送緩衝區和接收方的接收緩衝區都必須足夠大。

實際使用的窗口是接收方提供/請求的接收窗口的最小值以及發送方OS設置的發送緩衝區大小。

長話短說,您需要在服務器上配置發送緩衝區大小。

爲了清楚起見,我們來分析一下你的樣本數據包。

服務器發送數據的另一一束:

22 2.005109 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=19305 Ack=1 Win=65536 Len=1460 
23 2.005116 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=20765 Ack=1 Win=65536 Len=1460 
24 2.005121 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=22225 Ack=1 Win=65536 Len=1460 
25 2.005128 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  946 21500 > 57353 [PSH, ACK] Seq=23685 Ack=1 Win=65536 Len=892 

通知的PSH。這是一個標誌,表明在任何一跳之間已經發送完整的數據塊,請將其發送到另一端。 ( 「完整的」 塊是在這種情況下,你8KB)

在服務器仍在發送,它獲得2個ACKS:

26 2.005154 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=14601 Win=99999744 Len=0 
27 2.007106 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=16385 Win=99999744 Len=0 

請特別注意數字:Ack=14601Ack=16385。這些數字是接收器正在確認的數據包的序列號。 Ack = 14601表示「我收到了14601以後的所有東西」。

請注意,這些都是較舊的數據,不在您提供的樣本中。

所以服務器處理這些ACK和繼續發送數據:

28 2.007398 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=24577 Ack=1 Win=65536 Len=1460 
29 2.007401 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=26037 Ack=1 Win=65536 Len=1460 
30 2.007403 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=27497 Ack=1 Win=65536 Len=1460 
31 2.007404 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=28957 Ack=1 Win=65536 Len=1460 
32 2.007406 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=30417 Ack=1 Win=65536 Len=1460 
33 2.007408 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  946 21500 > 57353 [PSH, ACK] Seq=31877 Ack=1 Win=65536 Len=892 

在這裏,我們有一個完整的數據塊:1460 * 5 + 892 = = 8192

然後,發送後0.443毫秒去年包,它就會多一個ACK:

34 2.007883 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=19305 Win=99999744 Len=0 

然後還有的幾乎完全250ms的延遲,在此期間,服務器發送任何內容,則接收這些前:

35 2.257143 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=22225 Win=99999744 Len=0 
36 2.257160 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=24577 Win=99999744 Len=0 

,然後繼續發送:

37 2.257358 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=32769 Ack=1 Win=65536 Len=1460 
38 2.257362 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=34229 Ack=1 Win=65536 Len=1460 
39 2.257364 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=35689 Ack=1 Win=65536 Len=1460 
40 2.257365 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=37149 Ack=1 Win=65536 Len=1460 

有兩個非常有趣的事情在這裏看到。
首先,服務器發送多少字節而不等待ACK。 Te last ACK seq否在該延遲爲Ack=19305之前收到的服務器,並且該服務器在該點發送的最後一個數據包的seq否爲Seq=30417

在那個暫停期間,服務器發送的11112個字節尚未被客戶端確認。

其次,服務器在發送一堆數據後立即收到一個ACK,但沒有觸發它發送更多數據。就好像這個ACK不夠好。

在此之前收到的ACK是Ack=16385,給出30417-16385 = 14032個字節,這是由服務器在此時未發送確認的。只有在接收到seq no 24577的ACK後,將該計數減少到30417-24577 = 5840,服務器纔開始再次發送。

因此,8k的緩衝區大小與16k的有效窗口大小相比的事實意味着吞吐量實際上有所降低,因爲服務器將不會發送8k數據塊中的任何數據塊,直到所有數據都有空間。

最後,對於那些想知道的,有一個稱爲窗口縮放的TCP選項,它允許連接的一端聲明窗口大小實際上是TCP報頭中數字的一個倍數。見RFC 1323。該選項在SYN數據包中傳遞,因此它們在連接中不可見 - 僅提示窗口縮放有效,因爲窗口大小TCP標頭小於正在使用的窗口。

+0

Michael,該跟蹤的服務器發送緩衝區爲8kb(默認窗口大小)。我相信的痕跡是在客戶端被捕獲的。但你說得對:問題在於限制窗口的_SEND_緩衝區。我剛剛在服務器端運行了一個更大的發送者窗口的新測試,在阻止之前我可以清楚地看到更長的數據突發。 Wireshark中的圖形清楚地顯示了每次收到ACK時擁塞窗口是如何加倍的。 – fabrizi0 2012-04-24 13:53:53

0

在發送機接收到來自接收機的確認時,發送機已經排入了多少數據發送?由於TCP是基於流的協議,在數據流中沒有數據包中斷,因此TCP發送方無法知道應該何時發送部分數據包,以及何時應該等待更多數據到達。通常情況下,如果一個TCP實現接收到一個數據包的ACK,它會認爲它值得傳輸,直到傳輸緩衝區爲空,但是如果數據在傳輸之後排隊傳輸,它可能會等待,直到它發送另一個ACK批量。

+0

相信我,發件人緩衝區始終是滿的。我的應用程序儘可能快地寫入。這是一個for循環,它連續調用8Kb緩衝區的write()。 – fabrizi0 2012-04-23 23:47:02

0

接收器窗口大小直接影響吞吐量。吞吐量< = RWIN/RTT。

有幾件事情也可能會降低吞吐量。報頭中的ECN位是否設置爲1?你知道任何一方是否有包丟失?這似乎是服務器超時。您可以在客戶端打印傳入數據包和傳出ACK的序列號,並在服務器端打印類似信息。如果接收者的序列號是5,並且它接收到6,7,8,9,它將確認6,7,8,9。但是如果丟失了6個,它將在收到包7,8,9時收到ACK 5。序列號可以顯示很多信息。

250ms的暫停看起來像是暫停。

Slow-Start

該算法開始於指數生長期最初與1個或2段的擁塞窗口尺寸(cwnd的),並通過1個大小(SS)每個接收到的ACK增加它。由於接收器通常爲每兩個段發送一個ACK,所以這種行爲有效地使網絡每往返一次的窗口大小加倍。這種行爲一直持續到擁塞窗口大小(cwnd)達到接收者通告窗口的大小或發生丟失爲止。

什麼可以發生的是
服務器發送1個分組時,獲取1個ACK
服務器發送2個分組時,獲取2個的ACK(2,3)
服務器發送4個包,得到4次的ack(4,5- ,6,7)
服務器發送8個數據包,得到4個的ACK(數據包丟棄之前的客戶端得到了他們)(8,9,10,11)(超時12)
服務器發送4個包,得到4個的ACK(12,13 ,14,15)
服務器發送5個分組時,獲取4個的ACK(16,17,18,19)(超時20)
服務器發送3個數據包時,獲取3個的ACK(2 0,21,22)
服務器發送4個包,得到4個的ACK(23,24,25,26)
服務器發送5個分組時,獲取4個的ACK(27,28,29,30)(超時31)
服務器繼續3,4,5環

+0

賈斯汀。沒有丟包。我已經證實了這一點。我將嘗試從Wireshark獲取可打印的痕跡並將其發佈到此處。謝謝!!! – fabrizi0 2012-04-24 00:11:37

+0

ECN位可以由路由器設置。這會降低數據發送的速度。客戶端可能發送5個數據包,路由器正在設置ECN位或丟棄數據包。 ECN位是一種通知任何一方網絡是否擁塞的方法。 http://en.wikipedia.org/wiki/Explicit_Congestion_Notification – JustinDanielson 2012-04-24 00:16:19

+0

如果這是一個高延遲網絡,那麼沿途可能會有很多跳躍。接收器窗口可以像中間的瓶頸一樣大。但是如果這個瓶頸正在丟失數據包,接收者將永遠不會知道他們被髮送了。所以它會盡可能多地回覆數據包,而服務器會等待接收10個數據包而不是4個數據包。 – JustinDanielson 2012-04-24 00:19:56

1

一旦套接字連接,則不能設置> = 64K的接收緩衝區大小。你必須先做。在服務器的情況下,這意味着在偵聽套接字上設置接收緩衝區大小:可接受的套接字從它們接受的套接字繼承它。如果你不這樣做,那麼TCP窗口縮放選項就不能被協商,所以對等端無法告訴對方有關64k以上的大小。