參考文獻(xiàn): RFC2581, RFC3390
1. 前言
TCP是具備流控和可靠連接能力的協(xié)議,為防止TCP發(fā)生擁塞或?yàn)樘岣邆鬏斝剩诰W(wǎng)
絡(luò)發(fā)展早期就提出了一些相關(guān)的TCP流控和優(yōu)化算法,而且也被RFC2581規(guī)定是每個(gè)
TCP實(shí)現(xiàn)時(shí)要實(shí)現(xiàn)的。
本文中,為求方便把將“TCP分組段(segment)”都直接稱為“包”。
2. 慢啟動(dòng)(slow start)和擁塞避免(Congestion Avoidance)
慢啟動(dòng)和擁塞避免是屬于TCP發(fā)送方必須(MUST)要實(shí)現(xiàn)的,防止TCP發(fā)送方向網(wǎng)絡(luò)傳入大量的突發(fā)數(shù)據(jù)造成網(wǎng)絡(luò)阻塞。
先介紹幾個(gè)相關(guān)參數(shù),是在通信雙方中需要考慮但不在TCP包中體現(xiàn)的一些參數(shù):
擁塞窗口(congestion window,cwnd),是指發(fā)送方在接收到對(duì)方的ACK確認(rèn)前向允許網(wǎng)絡(luò)發(fā)送的數(shù)據(jù)量,數(shù)據(jù)發(fā)送后,擁塞窗口縮小;接收到對(duì)方的ACK后,擁塞窗口相應(yīng)增加,擁塞窗口越大,可發(fā)送的數(shù)據(jù)量越大。擁塞窗口初始值的RFC2581中被規(guī)定為不超過發(fā)送方MSS的兩倍,而且不能超過兩個(gè)TCP包,在RFC3390中更新了初始窗口大小的設(shè)置方法。
通告窗口(advertised window,rwnd),是指接收方所能接收的沒來得及發(fā)ACK確認(rèn)的數(shù)據(jù)量,接收方數(shù)據(jù)接收后,通告窗口縮小;發(fā)送ACK后,通告窗口相應(yīng)擴(kuò)大。
慢啟動(dòng)閾值(slow start threshold, ssthresh),用來判斷是否要使用慢啟動(dòng)或擁塞避免算法來控制流量的一個(gè)參數(shù),也是隨通信過程不斷變化的。
當(dāng)cwnd < ssthresh時(shí),擁塞窗口值已經(jīng)比較小了,表示未經(jīng)確認(rèn)的數(shù)據(jù)量增大,需要啟動(dòng)慢啟動(dòng)算法;當(dāng)cwnd > ssthresh時(shí),可發(fā)送數(shù)據(jù)量大,需要啟動(dòng)擁塞避免算法。
擁塞窗口cwnd是根據(jù)發(fā)送的數(shù)據(jù)量自動(dòng)減小的,但擴(kuò)大就需要根據(jù)對(duì)方的接收情況進(jìn)行擴(kuò)大,慢啟動(dòng)和擁塞避免算法都是描述如何擴(kuò)大該值的。
在啟動(dòng)慢啟動(dòng)算法時(shí),TCP發(fā)送方接收到對(duì)方的ACK后擁塞窗口最多每次增加一個(gè)發(fā)送方MSS字節(jié)的數(shù)值,當(dāng)擁塞窗口超過sshresh后或觀察到擁塞才停止算法。
啟動(dòng)擁塞避免算法時(shí),擁塞窗口在一個(gè)連接往返時(shí)間RTT內(nèi)增加一個(gè)最大TCP包長(zhǎng)度的量,一般實(shí)現(xiàn)時(shí)用以下公式計(jì)算:
cwnd += max(SMSS*SMSS/cwnd, 1) (2.1)
SMSS為發(fā)送方MSS。
TCP發(fā)送方檢測(cè)到數(shù)據(jù)包丟失時(shí),需要調(diào)整ssthresh,一般按下面公式計(jì)算:
ssthresh = max (FlightSize / 2, 2*SMSS) (2.2)
其中FlightSize表示已經(jīng)發(fā)送但還沒有被確認(rèn)的數(shù)據(jù)量。
3. 快速重傳(fast retransmit)和快速恢復(fù)(fast recovery)
TCP接收方收到錯(cuò)序的TCP包時(shí)要發(fā)送復(fù)制的ACK包回應(yīng),提示發(fā)送方可能出現(xiàn)網(wǎng)絡(luò)丟包;發(fā)送方
收到連續(xù)3個(gè)重復(fù)的ACK包后啟動(dòng)快速重傳算法,根據(jù)確認(rèn)號(hào)快速重傳那個(gè)可能丟失的包而不必等
重傳定時(shí)器超時(shí)后再重傳,普通的重傳是要等到重傳定時(shí)器超時(shí)還沒收到ACK才進(jìn)行的。這個(gè)算
法是TCP發(fā)送方應(yīng)該(SHOULD)實(shí)現(xiàn)的,不是必須。TCP發(fā)送方進(jìn)行了快速重傳后進(jìn)入快速恢復(fù)階段
,直到?jīng)]再接收重復(fù)的ACK包。
快速重傳和快速恢復(fù)具體過程為:
1. 當(dāng)收到第3個(gè)重復(fù)的ACK包時(shí),ssthreh值按公式2.2重新設(shè)置;
2. 重傳丟失的包后,將擁塞窗口cwnd設(shè)置為sshresh+3*SMSS,人工擴(kuò)大了擁塞窗口;
3. 對(duì)于每個(gè)接收到的重復(fù)的ACK包,cwnd相應(yīng)增加SMSS,擴(kuò)大擁塞窗口;
4. 如果新的擁塞窗口cwnd值和接收方的通告窗口值允許的話,可以繼續(xù)發(fā)新包;
5. 當(dāng)收到下一個(gè)ACK確認(rèn)了新數(shù)據(jù)時(shí),將cwnd大小調(diào)整為sshresh,減少窗口;對(duì)接收方
來說,接收到重發(fā)的TCP包后就要發(fā)此ACK確認(rèn)當(dāng)前接收的數(shù)據(jù)。
4. 結(jié)論
這些算法重點(diǎn)在于保持網(wǎng)絡(luò)的可靠性和可用性,防止網(wǎng)絡(luò)阻塞造成的網(wǎng)絡(luò)崩潰,是相對(duì)
比較保守的。
5. 附錄討論
A君: 這些算法都是針對(duì)通信雙方的事, 但如果從開發(fā)防火墻等中間設(shè)備的角度來看,
中間設(shè)備有必要考慮這些么?
端木: 這個(gè)...我好象也看不出必要性,因?yàn)樗惴ǖ膮?shù)都是在雙方內(nèi)部而不在TCP數(shù)據(jù)包
中體現(xiàn)...但應(yīng)該會(huì)讓中間設(shè)備輕松點(diǎn),這個(gè)就象在馬路開車,這些算法就是交規(guī)
讓你開得規(guī)矩點(diǎn),交警只關(guān)心你開車的情況,而不管你開的是什么車,開得好交警
也輕松。好車可以讓你很容易開好,但差車也可以開好。
A君: 這些算法原型提出也很早了, 最早是88年的事, 當(dāng)時(shí)網(wǎng)絡(luò)都處于初級(jí)階段, 有個(gè)
9600bps的貓就很牛了, 計(jì)算機(jī)性能也很差, 因此實(shí)施這些算法還有點(diǎn)用; 但現(xiàn)
在過了快20年了, 百兆都快淘汰, 千兆, 萬兆網(wǎng)絡(luò)都快普及了, 即使PC機(jī)的內(nèi)存
也都上G了,再規(guī)矩這種幾K級(jí)別的數(shù)據(jù)量有意思么? 就好象現(xiàn)在噴氣式戰(zhàn)斗機(jī)都到
第4代了, 再研究螺旋槳戰(zhàn)斗機(jī)還有意思么?
端木: 這個(gè)...這個(gè)就象病毒庫(kù)了, 里面不也有無數(shù)的DOS時(shí)代的病毒, 你以后這輩子估計(jì)
都見不著的,但沒有哪個(gè)防病毒廠商會(huì)把這些病毒從庫(kù)中剔除,庫(kù)是只增不減的。
有這么個(gè)東西也是一樣,正因?yàn)槠綍r(shí)沒用,誰也不注意,知道了就可以吹一吹,
尤其拿去唬唬人是很有效的!
A君: 你真無聊!
端木: You got it! 不無聊干嗎寫博客啊!
端木: 搞技術(shù)有時(shí)候是很悲哀的一件事,必須牽扯七大姑八大姨的很多老東西,也就是向下
兼容,到一定程度將成為進(jìn)一步發(fā)展的最大障礙,講一個(gè)從smth看到的不是笑話
的笑話:
現(xiàn)代鐵路的鐵軌間距是4英尺8點(diǎn)5英寸,鐵軌間距采用了電車輪距的標(biāo)準(zhǔn),而電車輪距
的標(biāo)準(zhǔn)則沿襲了馬車的輪距標(biāo)準(zhǔn)。
馬車的輪距為何是4英尺8點(diǎn)5英寸?原來,英國(guó)的馬路轍跡的寬度是4英尺8點(diǎn)5英寸。
如果馬車改用其他尺寸的輪距,輪子很快就會(huì)在英國(guó)的老馬路上撞壞。
英國(guó)馬路的轍跡寬度又從何而來?這可以上溯到古羅馬時(shí)期。整個(gè)歐洲(包括英國(guó))的老路都是羅馬人為其軍隊(duì)鋪設(shè)的,4英尺8點(diǎn)5英寸正是羅馬戰(zhàn)車的寬度。
羅馬戰(zhàn)車的寬度又是怎么來的?答案很簡(jiǎn)單,它是牽引一輛戰(zhàn)車的兩匹馬的屁股的總寬度。
段子到這里還沒有結(jié)束。美國(guó)航天飛機(jī)的火箭助推器也擺脫不了馬屁股的糾纏———火箭助推器造好之后要經(jīng)過鐵路運(yùn)送,而鐵路上必然有一些隧道,隧道的寬度又是根據(jù)鐵軌的寬度而來。代表著尖端科技的火箭助推器的寬度,竟然被兩匹馬的屁股的總寬度決定了。