轉(zhuǎn)載自微信公眾賬號:開點工作室(ID:kaidiancs)
擁塞控制(congestion control)是TCP協(xié)議的一項重要功能,TCP的擁塞控制機制是從端到端的角度,推測網(wǎng)絡(luò)是否發(fā)生擁塞,如果推斷網(wǎng)絡(luò)發(fā)生擁塞,則立即將數(shù)據(jù)發(fā)送速率降下來,以便緩解網(wǎng)絡(luò)擁塞。
TCP的擁塞控制采用的是窗口機制,通過調(diào)節(jié)窗口的大小實現(xiàn)對數(shù)據(jù)發(fā)送速率的調(diào)整。TCP的發(fā)送端維持一個稱為擁塞窗口cwnd的變量,單位為字節(jié),用于表示在未收到接收端確認的情況下,可以連續(xù)發(fā)送的數(shù)據(jù)字節(jié)數(shù)。cwnd的大小取決于網(wǎng)絡(luò)的擁塞程度,并且動態(tài)地發(fā)生變化。擁塞窗口調(diào)整的原則是:只要網(wǎng)絡(luò)沒有出現(xiàn)擁塞,就可以增大擁塞窗口,以便將更多的數(shù)據(jù)發(fā)送出去,相當于提高發(fā)送速率;一旦網(wǎng)絡(luò)出現(xiàn)擁塞,擁塞窗口就減小一些,減少注入網(wǎng)絡(luò)的數(shù)據(jù)量,從而緩解網(wǎng)絡(luò)的擁塞。
發(fā)送端判斷網(wǎng)絡(luò)發(fā)生擁塞的依據(jù)是:發(fā)送端設(shè)置一個重傳計時器RTO,對于某個已發(fā)出的數(shù)據(jù)報文段,如果在RTO計時到期后,還沒有收到來自接收端的確認,則認為此時網(wǎng)絡(luò)發(fā)生了擁塞。
TCP的擁塞控制算法包括了慢啟動(slow start)、擁塞避免(congestion avoidance)、快速重傳(fast retransmit)和快速恢復(fù)(fast recovery)四部分。
慢啟動算法作用在TCP數(shù)據(jù)傳輸?shù)拈_始階段,當主機開始發(fā)送數(shù)據(jù)時,因為不知道網(wǎng)絡(luò)中的負荷情況,如果立即發(fā)送大量的數(shù)據(jù),有可能會引起網(wǎng)絡(luò)的擁塞。因此,TCP采用試探的方法,逐漸增大擁塞窗口。通常在剛開始發(fā)送數(shù)據(jù)報文段時,先將擁塞窗口cwnd設(shè)置為一個TCP最大段長度MSS的值。而在每收到一個數(shù)據(jù)報文段的確認后,cwnd就增加一個MSS的數(shù)值。這樣就可以逐漸增大發(fā)送端的擁塞窗口,使數(shù)據(jù)注入網(wǎng)絡(luò)的速率比較合理。如果定義從發(fā)送端發(fā)出一個數(shù)據(jù)報文段到收到這個數(shù)據(jù)報文段的確認的時間間隔為往返時間RTT,則在慢啟動階段,每經(jīng)過一個RTT,cwnd的值就加倍。
為了防止擁塞窗口增長過快而引起網(wǎng)絡(luò)擁塞,TCP還需要設(shè)置一個慢啟動閾值ssthresh,當擁塞窗口的值增加到ssthresh時,就要減緩擁塞窗口的增長速度,具體的做法是每經(jīng)過一個RTT,擁塞窗口cwnd的值加1(單位為MSS),這樣就可以使cwnd按線性規(guī)律緩慢增長,這個過程稱之為“加性增加”(Additive Increase)算法。通常情況下,擁塞窗口cwnd的初值被設(shè)置為1,慢啟動閾值ssthresh的初值被設(shè)置為16。當擁塞避免算法執(zhí)行到某個時刻,發(fā)送端在規(guī)定時間內(nèi)沒有收到接收端的確認,即發(fā)生了網(wǎng)絡(luò)超時,則意味著網(wǎng)絡(luò)發(fā)生了擁塞。此時,發(fā)送端首先將ssthresh的值變?yōu)榘l(fā)生超時時cwnd值的一半,同時將cwnd的值置為1,重新執(zhí)行慢啟動算法。這樣做的好處是,當網(wǎng)絡(luò)頻繁出現(xiàn)擁塞時,ssthresh下降得很快,可以大大減少注入網(wǎng)絡(luò)中的數(shù)據(jù)報文段。通常稱這個過程為“乘性減小”(MultiplicativeDecrease)算法。TCP中的“加性增加”和“乘性減小”算法合起來稱為AIMD算法。
慢啟動和擁塞避免是1988年提出的擁塞控制算法,1990年在此基礎(chǔ)上又增加了快速重傳和快速恢復(fù)兩個算法。
快速重傳算法的基本思想是:接收端每收到一個失序的數(shù)據(jù)報文段后就立即發(fā)出重復(fù)確認,以便更早地通知發(fā)送端有丟包的情況發(fā)生。假設(shè)在某個TCP數(shù)據(jù)傳輸過程中,接收端依次收到發(fā)送端發(fā)出的1號和2號數(shù)據(jù)報文段,并對這兩個數(shù)據(jù)報文段發(fā)送確認后,沒有按次序收到3號數(shù)據(jù)報文段,而是收到了4號,這時就需要立即向發(fā)送端發(fā)送一個2號數(shù)據(jù)報文段的確認,稱為重復(fù)確認。同理,如果繼續(xù)收到5號、6號數(shù)據(jù)報文段,接收端仍然要向發(fā)送端發(fā)出2號數(shù)據(jù)報文段的重復(fù)確認。此時,發(fā)送端會收到多個2號數(shù)據(jù)報文段的重復(fù)確認,則認為3號數(shù)據(jù)報文段發(fā)生了丟包,需要立即向接收端重傳3號數(shù)據(jù)報文段,而不需要等待重傳計時器到期再重傳。快速重傳算法中規(guī)定如果收到某數(shù)據(jù)報文段的三個重復(fù)確認,則立即重傳下一個數(shù)據(jù)報文段。
快速恢復(fù)是配合快速重傳使用的算法,其基本思想是:當發(fā)送端連續(xù)收到三個重復(fù)確認時,就將慢啟動閾值ssthresh減半,以預(yù)防網(wǎng)絡(luò)擁塞的發(fā)生,并且將擁塞窗口cwnd的值置為減半后的ssthresh,然后開始執(zhí)行擁塞避免算法,使得cwnd緩慢地加性增大。
TCP擁塞控制算法描述如下:
SlowStartPhase( ) //慢啟動算法
{
CongWin=1; //擁塞窗口cwnd的初值為1個MSS
while (CongWin<Threshold&& 無數(shù)據(jù)丟失)
//當擁塞窗口小于慢啟動閾值且沒有發(fā)生丟包時
{
for each ACK
CongWin++; //每收到一個確認數(shù)據(jù)報,擁塞窗口加1
}
if (CongWin>=Threshold) then
CongestionAvoidancePhase( );
//當擁塞窗口大于等于慢啟動閾值時,啟動擁塞避免算法;
if (數(shù)據(jù)丟失) then
DataLoss( ); // 丟包后的處理方法
}
CongestionAvoidancePhase( ) // 擁塞避免算法
{
while (無數(shù)據(jù)丟失)
{
for each RTT
CongWin=CongWin+1; //每經(jīng)過一個RTT,擁塞窗口加1
}
DataLoss( );
}
DataLoss( ) //丟包后的處理方法
{
if (超時) then
{
Threshold=CongWin/2;
CongWin=1;
SlowStartPhase( );
//如果發(fā)生超時,慢啟動閾值置為當前擁塞窗口的一半,然后將擁塞窗口置1,開始執(zhí)行擁塞避免算法。
}
if (3次重復(fù)確認) then
{
Threshold=CongWin/2;
CongWin=CongWin/2;
CongestionAvoidancePhase();
//如果收到3個重復(fù)的確認,則執(zhí)行快速重傳和快速恢復(fù)算法,慢啟動閾值減小為擁塞窗口的一半,同時將擁塞窗口減半,開始擁塞避免算法