字節二面問我計算機網絡的擁塞控制問題,清明節假,我終於搞明白了...

多點頭髮,少點代碼git

本文已經收錄至個人GitHub,歡迎你們踊躍star 和 issues。github

https://github.com/midou-tech/articles面試

原本想先更新TCP的基礎和TCP可靠性等問題的,可是被大家暗示了,就先更流量控制和擁塞控制了。但願龍叔講的你能搞清楚,若是有不清楚的,能夠加龍叔微信一塊兒探討。算法

龍叔的號暫時還沒開通留言功能(你們要是有留言號,能夠貢獻一個出來喔😆),你們有什麼問題就直接後臺回覆龍叔便可加龍叔微信,享受一對一技術探討(只要是問我問題的都會回覆你們,基本是在晚上十點以後和週末,作好不會秒回的心理準備)緩存

流量控制

講流量控制以前先花簡短的話語絮叨下TCP基礎知識,詳細知識細節後面會出文章一一道來。bash

TCP是一種面向鏈接、保證可靠性、流式傳輸服務。面向鏈接就是創建連接,也就是面試常問的三次揮手創建連接,四次揮手斷開連接。保證可靠性到是很好理解,就是你發送的數據盡最大可能保證讓接收端接收到。流式傳輸 就是傳輸的數據是以字節流的形式發送和接受(不要硬是和我說,什麼字節流傳輸?明明物理層上都是波信號,這,抱拳。)微信

TCP傳輸數據都是創建連接以後才進行傳輸,傳輸的時候爲保證可靠性,也是採用確認應答機制。所謂確認應答機制就是發送數據以後必須收到確認消息,纔算一次有效傳輸。網絡

舉個簡單栗子,就是你和別人交流以前必須叫別人一聲(這位先生你好.... ,這位帥哥你好....,這位同窗你好.... 等等),對方收到你的消息,也會回覆一聲(你好,請問有什麼事?),緊接着纔會有下面的一堆交流。性能

試想若是沒有這個創建交流的過程,或者對方沒有回覆你,你的信息是沒法可靠的發送出去的。不過在傳輸協議裏還有一種能夠不考慮對方是否接受,只管本身消息發送出去便可,那就是UDP傳輸協議。學習

瞭解了TCP的確認應答機制以後方便講解下面的流量控制,接下來就好好看龍叔給你說流量控制究竟是怎麼一回事。

流量控制是保證可靠傳輸的方法之一,所謂流量控制本質就是控制TCP發送數據的速率,不要讓發送太快或者太慢讓接收方來不解接收或者沒東西可收。具體的控制方法或者機制是利用滑動窗口機制實現對TCP傳輸速率的控制。

這樣一說,是否是感受本身瞬間明白了一些,沒有那麼迷糊了。別急,下面還有硬核,必定讓你明白。

TCP報頭裏面有兩個字節專門表示滑動窗口大小,以下是TCP報頭。不用死記硬背,看看就好了。

看完這個圖應該很明確一點,TCP數據段的頭部中有2個字節專門表示窗口大小,這也就很明確另一個問題,每一個傳輸的TCP數據段都有2個字節表示窗口大小,而這2個字節就是流量控制的關鍵。

不要混淆TCP收發窗口和物理窗口,物理窗口大小是主機所配置的網卡緩衝區大小,通常是固定的,須要經過修改參數配置才能改變。

好比龍叔的網卡緩衝區的發送和接收緩衝大小。

[longshu /home/longshu] 15:04
$ cat  /proc/sys/net/core/rmem_max
212992

[longshu /home/longshu] 15:04
$ cat  /proc/sys/net/core/wmem_max
212992

TCP接收窗口大小是可變的(根據網絡傳輸狀況自適應調整大小)。

來一個滑動窗口的示例。

上面已經給出龍叔的主機物理髮送和接收窗口大小都是212992字節,爲了講解方便,先假設以下條件。

  • 發送端物理窗口爲1W字節
  • 每一個TCP數據段大小是1000字節
  • 用每一個數據段的首字段序號表示該數據段的序號

目前發送端收到了接收端發來的一個確認數據段,確認號爲3001,窗口大小爲5000,所以表示能夠連續發送10個數據段,數據段序號從3001~7001。

此時已經達到對方能接受的最大值,若是繼續發送數據可能會形成網絡擁堵等問題,在沒有接收到對方的確認序號和窗口大小以前,我方是不能發送數據的。

等待一會收到對方發來的確認序號爲6001,窗口大小爲4000,這表示對方已經收到了3001~6001四個數據段,而且能夠接收數據段大小爲4個,所以我方能夠繼續發送4個數據段,因爲以前發送出去的數據還沒徹底收到確認,此時只能發送800一、900一、10001這三個數據段,發送以後繼續等待收到確認應答號和窗口大小,才能進行下一次發送。

此時收到一個10001序號,窗口大小爲6000,就能夠連續發送10001~15001這6個數據段。如此往復的過程,就是基本的滑動窗口控制流量的過程。

滑動窗口工做過程以下圖。

過程圖解看起來會清晰不少,能夠清楚的知道滑動窗口每一次如何變化,以及如何收發。我最開始學習時很難理解滑動這個概念,以爲很抽象。如今看來滑動窗口就是未接受確認應答的數據段。

經過滑動窗口控制流量的方法也被稱爲 以收訂發的原則

忽然想到一個有趣的問題,前段時間我面試過一個粉絲,問到流量控制,對於整個滑動窗口流程答得很流暢,看他答得這麼順暢確定是準備充分,學習蠻不錯的。一想這流量控制就這點內容,就很少問了,準備問個簡單的問題就換下一個知識點。

因而我問他 假如對方給我確認應答序號,可接受窗口大小爲0,怎麼辦?

相信聰明的你必定知道如何回答了,不過龍叔仍是絮叨下。

首先對方在確認應答時能夠發送窗口大小爲0,這點是沒問題的。我方在收到對方窗口大小爲0時,不是一直等待着,此時我方會啓動一個定時器,定時發送一個試探報文給對方,試探報文沒有數據的,當對方回覆我方窗口大小不爲0時繼續傳輸數據;若是爲0,從新啓動計時器。

這個定時器叫 持續計時器

擁塞控制

擁塞控制問題也是網絡中常常遇到的問題,面試的時候若是遇到擁塞控制問題那你可算有福了,而後你再答對了,那簡直就是妥妥滴加分項啊。擁塞控制問題,通常面試官不會問。不要問我爲何,由於問十個同窗九個不會,面試官也沒啥興致再問了。

不誇張的講,TCP中最複雜的問題就是擁塞控制。因此你要是看龍叔的文章,懂了,就是賺了。拿到offer記得給龍叔福報。

網絡擁塞就像生活中的城市堵車同樣,各方面如此發達的現代社會,交通堵塞問題仍是一個頭疼的問題。到目前爲止尚未一個能徹底解決城市堵車問題的方案,目前全部的方法、政策、規則都是減輕、緩解堵塞問題,並無徹底解決。交通堵塞問題的成因多,時效強,多變。網絡結構但是比交通結構複雜不少倍

一般咱們衡量一個網絡的有效處理負荷的能力爲 吞吐量,把網絡中發送端輸入的負荷稱之爲 輸入負荷,理想狀況下網絡的輸入負荷和吞吐量之間的關係是以下圖的關係。

理想狀況下網絡的處理能力隨之輸入負荷的增大呈線性關係增大,到達網絡的最大處理能力時,吞吐量達到最大,此時不會隨着輸入負荷的增大而增大網絡吞吐量。

實際上網絡的處理能力是不會呈線性關係的,由於網絡不會有理想情況。就像咱們的常說的人生同樣,理想很豐滿,現實很骨感。

看完上面的講解你不要覺得那就簡單控制輸入負荷就能解決網絡擁塞問題,可沒那麼簡單的。

網絡擁塞的本質就是 對網絡資源的需求大於可用資源 ,可用資源是有限的,所以網絡擁塞問題是一直存在的。

從原理上講,尋找擁塞控制的方案無非就是減小網絡資源的需求和增大可用資源,使得二者可以平衡。具體措施有 增大網絡的某些可用資源(如業務繁忙時增長一些鏈路,增大鏈路的帶寬,或使額外的通訊量從另外的通路分流),或減小一些用戶對某些資源的需求 (如拒絕接受新的創建鏈接的請求,或要求用戶減輕其負荷,這屬於下降服務質量)。

但正如上面所講的,在採用某種措施時,還必須考慮到該措施所帶來的其餘影響。 實踐證實,擁塞控制是很難設計的,由於它是一個動態的(而不是靜態的)問題。

當前網絡正朝着高速化的方向發展,這很容易出現緩存不夠大而形成分組的丟 失。但分組的丟失是網絡發生擁塞的徵兆而不是緣由。

在許多狀況下,甚至正是擁塞控制機制自己成爲引發網絡性能惡化甚至發生死鎖的緣由。這點應特別引發重視。

雖然說網絡擁塞機制自己也有多是恐怖分子,但大多數時候仍是解決問題的關鍵。上面已經說清楚了網絡擁塞的緣由和本質,下面就來分析下有那些方法能夠避免和減小網絡擁塞。

目前解決網絡擁塞的方法主要有四種,慢開始、擁塞避免、快重傳、快恢復。

慢開始(慢啓動)

慢啓動可不是慢慢或者緩慢啓動喔,慢啓動指的是在網絡創建連接以後不當即發送最大數據段的數據,好比TCP最大數據段是1500字節,慢啓動會在創建鏈接以後第一次發送100個字節,收到確認後發送200字節,再次收到確認就發送300字節,依次增長直到達到最初設定的最大值。

唉,有人會說啦,前面流量控制講了發送窗口,這裏又有一個依次增長髮送數據段大小,這麼說難道發送窗口控制流量沒用了? 別急嘛,龍叔給你說清楚咋回事。

在慢啓動方案設計時,大佬們也意識到這個問題。不能發送窗口大小是1000,慢啓動增長到1500字節了,這到底依誰的?

慢啓動會維持一個擁塞控制窗口叫作 擁塞窗口(CWND)。每次發送出去的字節大小會是二者中的較小值。舉個例子,發送窗口能夠發送1500字節,可是此時擁塞窗口是1000字節,最終發送出去的字節就是1000字節。

擁塞窗口大小也是變化的。TCP創建完成後會有一個初始化的擁塞窗口大小。初始化擁塞窗口大小爲當前TCP連接使用的最大數據段大小(Maximum Segment Size,MSS)

當發送一次數據後,在定時器過時以前收到了確認應答消息(ACK),則擁塞窗口大小變爲原來的2倍,依次往復,只要在定時器過時以前能收到ACK,都會增大2倍。一直到數據分組發生丟失,這個發生丟分組的點叫作 慢啓動閾值(Slow Start Threshold,SSTHRESH),初始化慢啓動閾值是64KB。

到達閾值後擁塞窗口大小衰減爲最初的大小即1MSSS大小,慢啓動閾值衰減爲原來閾值的一半。此後又是一個新的慢啓動過程。不過擁塞窗口(CWND)再次到達慢啓動閾值(SSTHRESH)以後,會啓動擁塞避免機制。

擁塞避免

擁塞避免是在慢啓動的基礎上的,當慢啓動的擁塞窗口第二次達到閾值的時候啓動擁塞避免,這也說明都第二次時網絡必然是有些問題存在了。

擁塞避免就是控制擁塞窗口增加速度。以前慢啓動是擁塞窗口是以當前窗口大小的二倍速度增加的,如今網絡有問題啦,不能再以這種速度增大擁塞窗口了,否則一直這樣繼續估計最後網絡可傳輸的字節就是$2^\frac{1}{n}$,n趨近於無限大,可傳輸字節無限趨近於0。這就無法玩了,就是死鎖了。

因而擁塞避免在第二次慢啓動到達閾值後就使擁塞窗口呈線性增加而不是指數增加。弄個圖看下具體過程

快重傳

快重傳就是一個字快,在一個TCP數據段發送出去以後會啓動一個定時器,看是否接受ACK會超時。然而快重傳就是解決這個只能經過定時器超時才能判斷數據是否丟失的機制,達到快速判斷的效果,快速判斷才能早點發送已經丟失的數據。節省時間,減小網絡阻塞。

什麼狀況下才會觸發快重傳機制呢?可不是隨便一個數據段過來,就直接觸發快重傳了。

當接收端接收到不是按序到達的數據段時,此時接收端當即發送一個ACK響應報文,接收端接到三次重複ACK報文便可確認該數據段丟失,此時清零計時器,觸發重傳數據。

這一整個流程就是所謂的快重傳。快,沒話說吧。比你超時重傳快,根本不用等計時器超時。整個過程如圖所示。

快恢復

快恢復是在快重傳的基礎上的。當快重傳已經發送了丟失的數據後,快恢復機制被觸發。

在收到第三個重複ACK時,把當前CWND值設爲當前SSTHRESH值的一半,以減輕網絡負荷,而後執行前面介紹的「擁塞避免」算法,使CWND值慢慢增大,以免再次出現網絡擁塞。

綜上我基本說完了,擁塞控制的所有內容,若是有不明白的地方能夠私信龍叔一塊兒學習。

我是龍叔,一個分享互聯網技術和心路歷程的大叔。支持我,記得給我點贊和分享。

相關文章
相關標籤/搜索