TCP的重傳退避與公平

queue

TCP在發送報文後,如果沒有收到對端應答,那麼在重傳定時器超時後會觸發重傳,超時時間遵循二進制退避原則,也就是**{1,2,4,8,16}這樣成倍地擴大超時時間。退避是因爲TCP認爲丟包意味着網絡有擁塞,爲了不加重網絡的擁塞,TCP選擇等待更長的時間再進行重傳。這和CSMA/CD**中的二進制退避算法如出一轍。

鏈接曾經提到過網絡擁塞的來歷,網絡中的網絡設備(路由器、交換機)在收到了超過隊列限制的報文後,後續的報文會被丟棄。從TCP採用的二進制退避算來看,TCP絕對算得上是網絡裏的謙謙君子了,它信守的規則是:既然已經堵了,我就等一會兒再發,如果還堵,我就再多等翻倍的時間

對整個網絡來說,這的確是減輕負擔的好辦法。要知道,在發送窗口已滿的情況下,指數退避一次,意味着單位時間內發送的報文變成了原來的1/2,再退避一次,就只有原來的1/4!就像是汽車限號出行,單雙號限行不好用,我就規定一輛車只能在4天中開1天…

But, TCP真的需要如此剋制自己嗎?,換個說法,爲什麼TCP一定要x2退避?難道重傳定時器超時時間不能線性增大(每次增加X秒),或者乘以一個更小的係數(比如x1.5) ? 我們可以從CSMA/CD找到靈感。

CSMA/CD使用x2的原因很好理解,共享介質中的每個節點並不知道其他還有多少節點,使用x2退避就是利用二分法快速找到讓整個系統穩定運行的時隙分配方案!

舉個例子,假設系統中有4個節點發包速率相同,那麼最終的穩定分配方案自然就是將一段時間分爲4份,每個節點佔用1個時隙。如果此時又加入4個相同的節點。那麼顯然,所有的8個節點都會發包衝突。如何才能不衝突呢?當然是分配給每個節點的時間再減小一半!當然這裏舉的例子節點都是2的整數冪。如果不是呢?此時2進制退避依然能很快地達到穩定,也許這個時候的時隙分配方案不是最合理的,但是正如前面說的,每個節點並不知道其他還有多少節點,對單個節點來說,二進制退避是最快速找到讓每個節點都正常工作的方案!

sc1

二進制退避方案中隱含了對公平性的考慮,它是站在整個網絡的角度,而不是其中某一臺主機!

但對一臺特定的主機,不遵守這個退避規則顯然好處更多…比如使用固定的重傳定時器時間。在這種網絡中,沒有擁塞時大家相安無事,一旦出現了擁塞,那麼不退避的主機理論上就能發出更多的報文!

sc2

當然,這似乎犧牲了其他遵守規則主機的利益,它們的重傳次數會增加。那麼,如果大家都不遵守呢?結果就是大家的重傳次數都增加了,擁塞甚至比大家都遵守還要糟糕,因爲網絡上的設備丟的包更多了!

這就有點囚徒困境的味道了,如果別人退避你不退避,你能獲利,如果別人比退避而你退避,那麼你就喫虧了,如果大家都不遵守,那麼比都遵守還要糟糕…

當然,現實中的網絡並不同於CSMA/CD中的共享介質,一個簡單的區別就是,在CSMA/CD中,如果一個節點監聽到信道繁忙,它是不是發送數據的,它需要等待;而在網絡中,並不存在這樣的共享介質,並且路由器是又緩衝隊列的,因此兩個主機還是可以都發送報文。

話雖如此,很多遊戲爲了保證實時性不會選擇TCP !畢竟,TCP太無私了,它是爲了整個網絡考慮的。而實時遊戲需要的是什麼!快速!那麼如果它們有需要可靠傳輸怎麼辦? 很簡單,使用UDP,然後在用戶態自己做ARQ就好了,想怎麼折騰怎麼折騰,比如KCP就是這麼個東西。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章