原地址:http://blog.sina.com.cn/s/blog_c5c2d6690102wpxl.htmlhtml
TCP協議中影響實際業務流量的參數不少,這裏主要分析一下窗口的影響。算法
爲了得到最優的鏈接速率,使用TCP窗口來控制流速率(flow control),滑動窗口就是一種主要的機制。這個窗口容許源端在給定鏈接傳送數據分段而不用等待目標端返回ACK,一句話描述:窗口的大小決定在不須要對端響應(acknowledgement)狀況下傳送數據的數量。官方定義:「The amount of octets that can be transmitted without receiving an acknowledgement from the other side」。windows
TCP header中有一個Window Size字段,它實際上是指接收端的窗口,即接收窗口,用來告知發送端本身所能接收的數據量,從而達到一部分流控的目的。其實TCP在整個發送過程當中,也在度量當前的網絡狀態,目的是爲了維持一個健康穩定的發送過程,好比擁塞控制。所以,數據是在某些機制的控制下進行傳輸的,就是窗口機制。發送端的發送窗口是基於接收端的接收窗口來計算的,也就是咱們常說的TCP是有鏈接的發送,數據傳輸須要對端確認,發送的數據分爲以下四類來看api
(1)已經發送而且對端確認(Sent/ACKed)---------------發送窗外 緩衝區外緩存
(2)已經發送但未收到確認數據(Sent/UnACKed)----- --發送窗內 緩衝區內服務器
(3)容許發送但還沒有防的數據(Unsent/Inside)-----------發送窗內 緩衝區內網絡
(4)未發送暫不容許(Unsent/Outside)-------------------發送窗外 緩衝區內ide
TCP窗口就是這樣逐漸滑動,發送新的數據,滑動的依據就是發送數據已經收到ACK,確認對端收到,才能繼續窗口滑動發送新的數據。能夠看到窗口大小對於吞吐量有着重要影響,同時ACK響應與系統延時又密切相關。須要說明的是:若是發送端的窗口過大會引發接收端關閉窗口,處理不過來反之,若是窗口設置較小,結果就是不能充分利用帶寬,因此仔細調節窗口對於適應不一樣延遲和帶寬要求的系統很重要。學習
最先TCP協議涉及用來大範圍網絡傳輸時候,實際上是沒有超過56Kb/s的鏈接速度的。所以,TCP包頭中只保留了16bit用來標識窗口大小,容許的最大緩存大小不超過64KB。爲了打破這一限制,RFC1323規定了TCP窗口尺寸選擇,是在TCP鏈接開始的時候三步握手的時候協商的(SYN, SYN-ACK,ACK),會協商一個 Window size scaling factor,以後交互數據中的是Window size value,因此最終的窗口大小是兩者的乘積.優化
Window size value: 64 or 0000 0000 0100 0000 (16 bits)
Window size scaling factor: 256 or 2 ^ 8 (as advertised by the 1st packet)
The actual window size is 16,384 (64 * 256)
這裏的窗口大小就意味着,直到發送16384個字節,纔會中止等待對方的ACK.隨着雙方回話繼續,窗口的大小能夠修改window size value 參數完成變窄或變寬,可是注意:Window size scaling factor乘積因子必須保持不變。在RFC1323中規定的偏移(shift count)是14,也就是說最大的窗口能夠達到Gbit,很大。
這一機制並不老是默認開啓的和系統有關,貌似Linux默認開啓,Windows默認關閉。
TCP窗口起着控制流量的做用,實際使用時這是一個雙端協調的過程,還涉及到TCP的慢啓動(Rapid Increase/Multiplicative Decrease),擁塞避免,擁塞窗口和擁塞控制。能夠記住,發送速率是由min(擁塞窗口,接收窗口),接收窗口在下文有講。
TCP窗口既然那麼重要,那要怎麼設置,一個簡單的原則是2倍的BDP.這裏的BDP的意思是bandwidth-delay product,也就是帶寬和時延的乘積,帶寬對於網絡取最差鏈接的帶寬。
buffer size = 2 * bandwidth * delay
還有一種簡單的方式,使用ping來計算網絡的環回時延(RTT),而後表達爲:
buffer size = bandwidth * RTT
爲何是2倍?由於能夠這麼想,若是滑動窗口是bandwidth*delay,當發送一次數據最後一個字節剛到時,對端要回ACK才能繼續發送,就須要等待一次單向時延的時間,因此當是2倍時,恰好就能在等ACK的時間繼續發送數據,等收到ACK時數據恰好發送完成,這樣就提升了效率。
舉個例子:帶寬是20Mbps,經過ping咱們計算單向時延是20ms,那麼能夠計算:20000000bps*8*0.02 = 52,428bytes,所以咱們最優窗口用 104,856 bytes = 2 x 52,428,因此說當發送者發送104,856 bytes數據後才須要等待一個ACK響應,當發送了一半的時候,對端已經收到而且返回ACK(理想狀況),等到ACK回來,又把剩下的一半發送出去了,因此發送端就無需等待ACK返回。
發現了麼?這裏的窗口已經明顯大於64KB了,因此機制改善了,上一級。
如今咱們看看到底如何控制流量。TCP在傳輸數據時和windows size 關係密切,自己窗口用來控制流量,在傳輸數據時,發送方數據超過接收方就會丟包,流量控制,流量控制要求數據傳輸雙方在每次交互時聲明各自的接收窗口「rwnd」大小,用來表示本身最大能保存多少數據,這主要是針對接收方而言的,通俗點兒說就是讓發送方知道接收方能吃幾碗飯,若是窗口衰減到零,也就是發送方不能再發了,那麼就說明吃飽了,必須消化消化,若是硬撐脹漏了,那就是丟包了。
慢啓動 雖然流量控制能夠避免發送方過載接收方,可是卻沒法避免過載網絡,這是由於接收窗口「rwnd」只反映了服務器個體的狀況,卻沒法反映網絡總體的狀況。
爲了不網絡過載,慢啓動引入了擁塞窗口「cwnd」的概念,用來表示發送方在獲得接收方確認前,最大容許傳輸的未經確認的數據。「cwnd」同「rwnd」相比不一樣的是:它只是發送方的一個內部參數,無需通知給接收方,其初始值每每比較小,而後隨着數據包被接收方確認,窗口成倍擴大,有點相似於拳擊比賽,開始時不瞭解敵情,每每是次拳試探,慢慢內心有底了,開始逐漸加大重拳進攻的力度。
在慢啓動的過程當中,隨着「cwnd」的增長,可能會出現網絡過載,其外在表現就是丟包,一旦出現此類問題,「cwnd」的大小會迅速衰減,以便網絡可以緩過來。
說明:網絡中實際傳輸的未經確認的數據大小取決於「rwnd」和「cwnd」中的小值。
擁塞避免 從慢啓動的介紹中,咱們能看到,發送方經過對「cwnd」大小的控制,可以避免網絡過載,在此過程當中,丟包與其說是一個網絡問題,倒不如說是一種反饋機制,經過它咱們能夠感知到發生了網絡擁塞,進而調整數據傳輸策略,實際上,這裏還有一個慢啓動閾值「ssthresh」的概念,若是「cwnd」小於「ssthresh」,那麼表示在慢啓動階段;若是「cwnd」大於「ssthresh」,那麼表示在擁塞避免階段,此時「cwnd」再也不像慢啓動階段那樣呈指數級整整,而是趨向於線性增加,以期避免網絡擁塞,此階段有多種算法實現,一般保持缺省便可,這裏就不一一說明了。
如何調整「rwnd」到一個合理值 不少時候TCP的傳輸速率異常偏低,頗有多是接收窗口「rwnd」太小致使,尤爲對於時延較大的網絡,實際上接收窗口「rwnd」的合理值取決於BDP的大小,也就是帶寬和延遲的乘積。假設帶寬是 100Mbps,延遲是 100ms,那麼計算過程以下:
BDP = 100Mbps * 100ms = (100 / 8) * (100 / 1000) = 1.25MB
此問題下若是想最大限度提高吞度量,接收窗口「rwnd」的大小不該小於 1.25MB。
如何調整「cwnd」到一個合理值 通常來講「cwnd」的初始值取決於MSS的大小,計算方法以下:
min(4 * MSS, max(2 * MSS, 4380))
以太網標準的MSS大小一般是1460,因此「cwnd」的初始值是3MSS。當咱們瀏覽視頻或者下載軟件的時候,「cwnd」初始值的影響並不明顯,這是由於傳輸的數據量比較大,時間比較長,相比之下,即使慢啓動階段「cwnd」初始值比較小,也會在相對很短的時間內加速到滿窗口,基本上能夠忽略不計。下圖使用IxChariot完成一次設置
不過當咱們瀏覽網頁的時候,狀況就不同了,這是由於傳輸的數據量比較小,時間比較短,相比之下,若是慢啓動階段「cwnd」初始值比較小,那麼極可能還沒來得及加速到滿窗口,通信就結束了。這就比如博爾特參加百米比賽,若是起跑慢的話,即使他的加速很快,也可能拿不到好成績,由於還沒等他徹底跑起來,終點線已經到了
文中大量參考下面博客內容,好比最後一節幾乎徹底來自於第一個博客,詳細內容跳轉連接,學習總結,記錄一下。
https://huoding.com/2013/11/21/299
https://my.oschina.net/greki/blog/264061
http://www.cnblogs.com/woaiyy/p/3554182.html