
簡介本資源為高級計算機網(wǎng)絡與網(wǎng)絡通信技術課程第7章「擁塞控制與流量控制」的配套課件面向高校計算機、通信工程專業(yè)學生及備考網(wǎng)絡方向的學習者幫助系統(tǒng)掌握擁塞控制與流量控制的核心原理與算法。內(nèi)容圍繞擁塞產(chǎn)生條件、開環(huán)與閉環(huán)控制、緩沖區(qū)預分配、分組丟棄法、定額擁塞控制、抑制信息包法及限制輸出隊列長度等策略展開并深入講解TCP慢啟動、擁塞避免、快速重傳與快速恢復算法以及TCP友好擁塞控制與隨機早期檢測RED機制配有直接死鎖、重裝死鎖等實例分析。資源包共1個pptx文件約1.02MB以幻燈片形式呈現(xiàn)80頁課程內(nèi)容結構清晰、圖文并茂便于課堂講授與課后復習。目前已有97人學習適合需要梳理擁塞控制知識框架、對照算法細節(jié)與典型實例查漏補缺的讀者。1. 擁塞控制與流量控制一份 80 頁課件背后真正要講清的兩件事很多人第一次翻到「擁塞控制與流量控制」這一章會下意識把這兩個詞當成一回事畢竟都跟「別發(fā)太快」有關。但真到抓包、調(diào)參、排查線上吞吐上不去的時候你會發(fā)現(xiàn)它們根本是兩個層面的問題流量控制是點對點的解決的是「接收方來不及收」靠的是滑動窗口和接收窗口 rwnd擁塞控制是端到端的解決的是「網(wǎng)絡中間扛不住」靠的是擁塞窗口 cwnd 和一整套 AIMD、慢啟動、快重傳快恢復的機制。一份 80 頁的課件真正值錢的部分不是那些狀態(tài)機圖而是把「發(fā)送方到底按誰的限制發(fā)」這件事講透——發(fā)送窗口 min(rwnd, cwnd)。這篇筆記就順著這個標題把課件里最容易講糊的地方拆成能復現(xiàn)、能驗證、能踩坑的實操路徑適合正在學計算機網(wǎng)絡、準備期末或 408以及需要把 TCP 行為講給團隊聽的工程師。2. 流量控制滑動窗口到底在滑動什么流量控制的核心一句話接收方通過 TCP 首部里的窗口字段告訴發(fā)送方「我還能收多少字節(jié)」。這個字段是 16 位最大 65535 字節(jié)所以高帶寬時延積鏈路上必須靠窗口擴大選項Window Scaling撐開否則吞吐會被死死卡住。課件里通常只畫一個滑動窗口示意圖但真正要理解的是三個指針發(fā)送已確認、發(fā)送未確認、可發(fā)送邊界以及接收方那個 rwnd 是怎么隨應用層讀取速度動態(tài)變化的。2.1 滑動窗口的四個邊界與 rwnd 的實時性發(fā)送方維護的窗口可以拆成四段已發(fā)送且已確認、已發(fā)送未確認、可發(fā)送但未發(fā)送、不可發(fā)送。接收方回送的 ACK 里帶的 rwnd決定的是「可發(fā)送但未發(fā)送」這一段的上限。這里有個容易被忽略的點rwnd 是接收方當前剩余緩沖不是固定值。應用層讀得慢rwnd 就縮讀得快rwnd 就漲。所以你會看到同一個連接里窗口字段一直在變這不是玄學是接收緩沖在實時反饋。零窗口是流量控制里最經(jīng)典的場景。接收方緩沖滿了回一個 rwnd0 的 ACK發(fā)送方必須停發(fā)然后啟動持續(xù)計時器persist timer周期性發(fā)零窗口探測防止死鎖——因為窗口更新的 ACK 如果丟了雙方就會一直等下去。這個探測報文只帶 1 字節(jié)數(shù)據(jù)收到后接收方重新通告窗口。2.2 用 ss 和 tcpdump 看窗口的真實變化光看圖不夠得看真實連接。Linux 上用ss能直接看到發(fā)送和接收隊列配合tcpdump抓窗口字段就能把課件里的靜態(tài)圖變成動態(tài)過程。# 查看當前 TCP 連接的發(fā)送/接收隊列和窗口相關狀態(tài) ss -tin state established ( dport :80 or sport :80 ) # 抓包只看 TCP 窗口字段變化-S 顯示絕對序列號便于對齊 sudo tcpdump -i eth0 -nn -S tcp port 80 and (tcp[tcpflags] tcp-ack ! 0)ss -tin里的skmem一行會顯示rb接收緩沖和tb發(fā)送緩沖的用量rcv_space是接收方通告的窗口上限。tcpdump抓到的每個 ACK 報文win后面的數(shù)字就是當時的 rwnd。把這兩個對照著看你就能確認「接收方讀得慢 → rwnd 縮小 → 發(fā)送方被限流」這條鏈路。參數(shù)上注意-S用絕對序列號方便你算窗口滑動了多少不加-S是相對序列號看趨勢可以算具體字節(jié)數(shù)容易亂。2.3 窗口擴大選項65535 不夠用的時候高帶寬時延積鏈路比如 100ms RTT、1Gbps帶寬時延積是 12.5MB16 位窗口最大 64KB吞吐直接被壓到 64KB/0.1s 5.2Mbps連百分之一都跑不到。窗口擴大選項在三次握手時協(xié)商一個移位因子0~14把窗口字段左移最大能到 2^30 左右。這個選項只在 SYN 和 SYN-ACK 里出現(xiàn)連接建立后就不能改了。# 查看系統(tǒng)是否開啟窗口擴大以及相關緩沖上限 sysctl net.ipv4.tcp_window_scaling sysctl net.ipv4.tcp_rmem sysctl net.ipv4.tcp_wmemtcp_window_scaling為 1 表示開啟默認就是開的。tcp_rmem和tcp_wmem三個值分別是 min、default、max接收緩沖 max 太小會限制 rwnd 上限進而限制窗口擴大能發(fā)揮的作用。常見做法是把 max 調(diào)到幾十 MB具體看你的帶寬時延積。這里有個坑窗口擴大因子是握手時定的如果你中途改了tcp_rmem已建立的連接不會變得重連才生效。3. 擁塞控制從慢啟動到 CUBIC 的落地觀察擁塞控制和流量控制最大的區(qū)別是rwnd 是別人告訴你的cwnd 是你自己猜的。發(fā)送方?jīng)]有任何字段能直接讀到網(wǎng)絡中間隊列有多滿只能靠 ACK 到達的節(jié)奏、丟包、RTT 變化來推斷。這就是為什么擁塞控制算法這么多——Reno、NewReno、CUBIC、BBR本質(zhì)都是對「網(wǎng)絡什么時候算擁塞」的不同假設。課件里通常重點講 Reno 的四階段但生產(chǎn)環(huán)境里 Linux 默認早就是 CUBIC 了得知道兩者差別在哪。3.1 慢啟動、擁塞避免、快重傳、快恢復的邊界條件慢啟動cwnd 從 1 個 MSS 開始每收到一個 ACK 就加 1 MSS效果是指數(shù)增長直到 cwnd 達到慢啟動閾值 ssthresh。擁塞避免cwnd 超過 ssthresh 后每個 RTT 只加 1 MSS線性增長。這兩個階段的分界就是 ssthresh初始值通常設成一個很大的數(shù)第一次丟包后才被賦值為當時 cwnd 的一半??熘貍鞯挠|發(fā)條件是收到 3 個重復 ACK不等超時就直接重傳丟失的段。快恢復是在快重傳之后把 ssthresh 設為 cwnd 的一半cwnd 設為 ssthresh有的實現(xiàn)是 ssthresh3然后進入擁塞避免。超時重傳則更狠ssthresh 減半cwnd 直接回到 1重新慢啟動。這個區(qū)別是考試高頻點也是理解「為什么丟包恢復后吞吐掉得不一樣」的關鍵。3.2 用 ss 看 cwnd 和擁塞算法用 ip route 換算法Linux 上ss -ti能直接看到每個連接的 cwnd、ssthresh、rtt、retrans 等擁塞相關字段這是把課件理論對上真實連接最快的方式。# 查看連接級擁塞信息關注 cwnd、ssthresh、rtt、retrans ss -ti state established ( dport :443 or sport :443 ) # 查看當前系統(tǒng)默認擁塞控制算法 sysctl net.ipv4.tcp_congestion_control # 查看內(nèi)核支持哪些算法 sysctl net.ipv4.tcp_available_congestion_control # 臨時切換成 CUBIC 或 BBR需內(nèi)核支持 sudo sysctl -w net.ipv4.tcp_congestion_controlcubicss -ti輸出里cwnd:后面是當前擁塞窗口單位是 MSS 數(shù)ssthresh:是慢啟動閾值rtt:是平滑 RTTretrans:是重傳計數(shù)。如果你看到 cwnd 長時間卡在一個小值、retrans 一直漲基本就是鏈路在丟包擁塞控制在壓著發(fā)。切換算法用sysctl -w是全局的只影響新連接要對單個連接生效得在應用層用setsockopt的TCP_CONGESTION選項這個課件一般不講但實際調(diào)優(yōu)常用。3.3 CUBIC 和 Reno 的差別為什么默認換了Reno 的擁塞窗口是線性的長肥管道高帶寬高時延上恢復太慢。CUBIC 把窗口增長改成三次函數(shù)離上次擁塞點越遠增長越快越近增長越慢整體更平滑在高帶寬鏈路上吞吐明顯更好。BBR 則完全不看丟包而是建模瓶頸帶寬和最小 RTT在有一定丟包的鏈路上優(yōu)勢明顯但和 CUBIC 共存的公平性一直有爭議。# 對比同一連接在不同算法下的 cwnd 增長可寫腳本定時采樣 for i in $(seq 1 20); do ss -ti state established ( dport :443 ) | grep -o cwnd:[0-9]* sleep 1 done這段腳本每秒采一次 cwnd跑 20 秒你就能看到窗口增長的形狀。CUBIC 前期漲得快接近擁塞點時變緩Reno 是穩(wěn)定線性。參數(shù)上注意采樣間隔要小于 RTT 的若干倍才有意義間隔太大只能看趨勢。這個對比方法比死記公式直觀得多也是我一般給學生演示時用的手段。4. 避坑與排查擁塞控制里最容易翻車的五個點4.1 把 rwnd 和 cwnd 搞混調(diào)優(yōu)方向全錯現(xiàn)象吞吐上不去有人去調(diào)tcp_rmem加大接收緩沖結果沒變化。原因瓶頸在 cwnd 不在 rwnd接收方窗口一直很大是網(wǎng)絡在丟包壓著發(fā)送方。解決先用ss -ti看 cwnd 和 retrans如果 cwnd 小且 retrans 漲是擁塞問題調(diào)接收緩沖沒用如果 rwnd 小才是接收方讀得慢。兩個窗口取 min得先確認哪個是短板。4.2 窗口擴大沒生效吞吐卡在 64KB 附近現(xiàn)象高時延鏈路上吞吐怎么都上不去抓包看窗口字段最大就 65535。原因窗口擴大選項沒協(xié)商成功可能是中間設備改寫了 SYN或者一端沒開。解決抓三次握手報文看 SYN 和 SYN-ACK 里有沒有 Window Scale 選項因子是多少。如果一端沒發(fā)檢查net.ipv4.tcp_window_scaling。注意這個選項握手后不能改必須重連。4.3 快重傳沒觸發(fā)一直等超時現(xiàn)象丟了一個段連接卡了很久才恢復抓包看到重復 ACK 不到 3 個。原因丟包位置在窗口末尾后面沒有足夠多的段來產(chǎn)生重復 ACK快重傳條件湊不齊。解決這是快重傳的固有局限NewReno 用部分 ACK 緩解但根本還是靠 SACK選擇性確認。檢查net.ipv4.tcp_sack是否為 1開了之后接收方能告訴發(fā)送方具體缺哪段恢復更快。4.4 切換擁塞算法后老連接沒變現(xiàn)象sysctl -w換了算法但現(xiàn)有連接吞吐沒變化。原因擁塞算法是連接建立時綁定的改全局默認只影響新連接。解決要影響已有連接得在應用層用setsockopt設TCP_CONGESTION或者重啟應用重建連接。這個坑在線上調(diào)優(yōu)時特別常見改完以為生效了其實老連接還在跑舊算法。4.5 零窗口探測被防火墻攔掉現(xiàn)象接收方緩沖滿發(fā)了零窗口之后連接就死了雙方都不動。原因零窗口探測報文很小有些中間設備或防火墻會丟棄這種「空」報文導致窗口更新永遠傳不過去。解決抓包確認探測報文有沒有發(fā)出去、有沒有被回。如果是中間設備問題只能調(diào)整設備策略應用層能做的是盡量讓接收方及時讀走數(shù)據(jù)別讓窗口真的歸零。5. 把課件變成能驗證的實驗三個進階技巧學完這一章最怕的就是「圖都看懂了一到真實連接就懵」。我的習慣是每講一個機制就設計一個能觀測它的最小實驗。第一個技巧是用tc人為制造丟包和時延觀察 cwnd 怎么反應。比如在回環(huán)口上加 5% 丟包然后跑一個長連接用ss -ti采樣 cwnd你會看到 CUBIC 在丟包后窗口掉一半再慢慢爬這個曲線比任何圖都直觀。# 在 eth0 上模擬 100ms 時延和 2% 丟包觀察擁塞窗口行為 sudo tc qdisc add dev eth0 root netem delay 100ms loss 2% # 實驗結束后清除規(guī)則 sudo tc qdisc del dev eth0 rootnetem的delay和loss是最常用的兩個參數(shù)delay影響 RTT 進而影響窗口增長速度loss直接觸發(fā)擁塞控制。注意實驗要在測試環(huán)境做別在生產(chǎn)網(wǎng)卡上加規(guī)則。第二個技巧是對比 SACK 開關前后的恢復速度把tcp_sack關掉再跑同樣的丟包場景你會發(fā)現(xiàn)恢復慢很多這就把「SACK 為什么重要」講實了。第三個技巧是畫一張自己的對照表把流量控制和擁塞控制在每個維度上列清楚這比背定義有用得多。維度流量控制擁塞控制作用范圍點對點發(fā)送方-接收方端到端發(fā)送方-整個網(wǎng)絡反饋來源接收方通告的 rwndACK 節(jié)奏、丟包、RTT 推斷核心變量rwndcwnd典型機制滑動窗口、零窗口探測慢啟動、擁塞避免、快重傳快恢復失控后果接收方緩沖溢出網(wǎng)絡中間隊列溢出、全局擁塞崩潰這張表我一般讓學生自己填一遍填不出來的格子就是沒理解的地方。最后說個我自己的教訓早年調(diào)一個跨機房同步任務吞吐一直上不去我第一反應是加接收緩沖折騰半天沒效果后來ss -ti一看 cwnd 卡在 10 左右、retrans 一直漲才知道是中間鏈路丟包擁塞控制在壓著。從那以后我養(yǎng)成了一個習慣——任何吞吐問題先看 cwnd 和 retrans再看 rwnd順序反了就是白費功夫。希望幫到你。本文還有配套的精品資源點擊獲取