tcp/ip 擁塞控制、重傳、丟包、優化


弱網環境是丟包率較高的特殊場景,TCP 在類似場景中的表現很差,當 RTT 為 30ms 時,一旦丟包率達到了 2%,TCP 的吞吐量就會下降 89.9%[3],從下面的表中我們可以看出丟包對 TCP 的吞吐量極其顯著的影響:

概念理解

4種計時器

1.重傳計時器:Retransmission Timer A發報文時創建計時器,計時器到期內收到回報文ACK,就撤銷計時器

2.持久計時器:Persistent Timer B告訴A,接收窗口填滿了(0窗口通報),告訴A停止發送,進入等待,直到B發送報文告訴A已有“非零窗口”,但此時若這個報文丟失,B自己不知道,等着A發數據過來,雙方都進入等待死鎖,解決這個問題要在A端創建持久計時器,當收到B發送過來的0窗口通報報文后,計時器啟動,計時器過期后,A發一個探測報文給B,詢問是否有非0窗口,如果超時還沒ack恢復則發探查報文,如果超時前收到到ack回復依然是0窗口,則將計時器復位並且翻倍時間值(1,2,4,8最大60s),如此循環,直到收到B的重開窗口確認包。

3.保活計時器:Keeplive Timer 長連接中A發送數據給B,發送幾個數據包之后,A出故障了,B等待2小時后發10個探測報文段(每個75分鍾發一次),如果沒有響應就終止連接

4.時間等待計時器:Timer_Wait Timer time_wati狀態下發出的給被關閉端ack報文后等待時間(30~120s),一般設置一個msl(最長報文壽命)是60s

包重傳的原因

tcp可靠性通過序列號和ack確認包保障,當tcp發送包之后,將這個包的副本數據段放到重傳隊列上啟動重傳計時器
1、如果對方反饋ack,則銷毀數據段和計時器
2、如果對方沒有反饋ack,則在計時器到期后發起重傳

快速重傳:A向B發送4個tcp報文段(n1,n2,n3,n4),B只收到(n1,n2,n4),其中n3丟失(也許只是延時到達),B發現失序立即生成 重復ACK包(重復確認n3),且發送三次給A,A重傳該數據包

超時重傳:定時器超時之后,重傳包,計時器的時間為“大於平均往返延遲”

偽超時和重傳:過早的判斷了超時時間,導致發送方觸發重傳,RTT(連接往返時間)增長 超過RTO(重傳超時時間)

包失序:ip層的包沒有按順序傳輸,嚴重失序時,接收方誤以為包丟失,通知發送端重傳,需要設置合理的重傳閥值解決

包重復:重傳包含一個數據包,以及兩個副本,多次重復會導致B收到過多重復包,從而B生成重復的ack,容易觸發偽快速重傳,使用sack避免

sack:當出現包失序、網絡丟包導致的接收方數據序隊列出現空洞,sack選項可以提供確認信息(描述亂序、空洞),幫助A方有效的重傳。

擁塞控制

作用1:防止A向B發送過多數據,導致B無法處理
作用2:防止tcp任意連接的一方向網絡發送大量數據,導致網絡擁塞崩潰

擁塞窗口大小(cwnd),雙方的接收窗口大小(rwnd)

tcp三次握手中雙方通過ack交換接收窗口大小,rwnd有帶寬延遲乘積決定
客戶端能同時傳輸的最大數據段的數量值就是 cwnd和接收方rwnd的最小值min(cwnd,rwnd),在linux中為tcp_init_cwnd10,就是10個
tcp傳輸中A的擁塞窗口大小根據B的響應進行調整
1、線性增長:經過一個RTT,擁塞窗口大小會加一(是不是慢啟動)
2、積式減少:發送方發送的數據丟包的時候,擁塞控制 閥值會減半

例如默認linux,A同時能發10個數據段,我們網絡是10M,RTT是40ms,每個數據段1460字節,根據BDP(帶寬延遲積)計算,雙方窗口大小上限35
a>b 10段 0.5RTT
a<b 0.5RTT
a>b 10段+10 0.5RTT 經過一次rtt,窗口段數加倍
a<b 0.5RTT
a>b 20段+20 0.5RTT 經過二次rtt,窗口段數加倍
第三次開始(3.5RTT)窗口數穩定在上限35,需要140ms時間
三次握手就是1.5RTT

弱網環境下(丟包率高)導致 TCP 性能問題的三個重要原因:

TCP 的擁塞控制在發生丟包時會進行退讓,減少能夠發送的數據段數量,但是丟包並不一定意味着網絡擁塞,更多的可能是網絡狀況較差;
TCP 的三次握手帶來了額外開銷,這些開銷不只包括需要傳輸更多的數據,還增加了首次傳輸數據的網絡延遲;
TCP 的重傳機制在數據包丟失時可能會重新傳輸已經成功接收的數據段,造成帶寬的浪費;

優化

QUIC 協議是能否保證丟包率較高時的傳輸性能 https://blog.csdn.net/m0_37621078/article/details/106506532
除了 SACK 和 TFO 之外還有哪些手段可以優化 TCP 的性能?

了解接收數據庫包的流程

1、網卡收到數據包
2、將數據包從網卡硬件緩存轉移到服務器內存中。
3、通知內核處理
4、經過icp/ip協議逐層處理
5、應用程序通過read()從socket buffer讀取數據

網卡接收數據包轉移到主機內存

1、驅動在內存創建一塊緩沖區(sk_buffer)
2、驅動將這個緩沖區的地址、大小信息(即接收描述符)加入到rx_ring_buffer。緩沖區地址是DMA使用的物理地址
3、驅動通知網卡有個新描述符
4、網卡從rx_ring_buffer取出描述符,得知緩沖區地址和大小
5、網卡將數據包通過DMA直接寫到sk_buffer

網卡丟包原因1

驅動處理速度跟不上網卡接收包速度,驅動來不及分配緩沖區,網卡的數據無法實時寫到sk_buffer,導致網卡內存緩沖區寫滿,開始丟棄部分數據,引起丟包。這部分丟包為rx_fifo_errors,在/proc/net/dev 中體現為filo 字段增長,在ifconfig 中體現為overruns指標增長。

網卡發起硬中斷通知內核處理

硬中斷:由硬件自己生產,具有隨機性,硬中斷被cpu接收后,觸發執行中斷處理程序,中斷程力程序只會處理關鍵性、短時間內可完成的工作,剩余耗時交給軟中斷完成。(上半部分)

軟中斷:由硬中斷對應的中斷處理程序生成,一般是代碼內實現好的,不具隨機性。(下半部分)

數據被網卡通過DMA寫到sk_buffer,網卡立即發起一個硬中斷。cpu接收后,首先進入上半部分,cpu中斷處理后,由網卡驅動程序發起軟中斷處理,進入下半部分,軟中斷處理程序開始消費sk_buffer 中的數據,交給內核協議棧處理。

通過中斷,能夠快速響應網卡數據請求,但是如果數量大,硬中斷過多,導致cpu大量時間處理中斷,效率降低。解決方案是內核、驅動采用NAP(new api)進行處理數據,即輪詢+中斷,數據量大時,一次硬中斷后通過輪詢接收一定數量數據包才后返回,減少硬中斷導致的效率降低。

ifconfig 下重點字段意思

RX errors 總的收包的錯誤數量,包含 too-long-frames 錯誤,Ring Buffer 溢出錯誤,crc 校驗錯誤,幀同步錯誤,fifo overruns 以及 missed pkg 等等

RX dropped 表示數據包已經進入了網卡的接收緩存fifo隊列 Ring Buffer,並且開始被系統中斷處理准備進行數據包拷貝(從網卡緩存fifo隊列拷貝到系統內存),但由於此時的系統原因(比如內存不夠等)導致這個數據包被丟掉,即這個數據包被Linux系統丟掉。

RX overruns 表示了 fifo 的 overruns,這是由於 Ring Buffer(aka Driver Queue) 傳輸的 IO 大於 kernel 能夠處理的 IO 導致的,而 Ring Buffer 則是指在發起 IRQ 中斷請求之前的那塊 buffer。表示這個數據包還沒有被進入到網卡的接收緩存fifo隊列就被丟掉,因此此時網卡的fifo是滿的。為什么fifo會是滿的?因為系統繁忙,來不及響應網卡中斷,導致網卡里的數據包沒有及時的拷貝到系統內存,fifo是滿的就導致后面的數據包進不來,即這個數據包被網卡硬件丟掉。所以,個人覺得遇到overruns非0,需要檢測cpu負載與cpu中斷情況。很明顯,overruns 的增大意味着數據包沒到 Ring Buffer 就被網卡物理層給丟棄了,而 CPU 無法及時的處理中斷是造成 Ring Buffer 滿的原因之一,這樣就會導致因為 interruprs 分布的不均勻 (都壓在 core0),沒有做 affinity 而造成的丟包。

RX frame 表示 misaligned 的 frames。

error是出現了網絡錯誤,dropped是出現了格式不正確被丟棄的包,overruns 驅動緩沖不足或者網絡中斷處理不及時導致的緩沖溢出的數量

丟包排查思路

網卡工作在數據鏈路層,數據量鏈路層,會做一些校驗,封裝成幀。我們可以查看校驗是否出錯,確定傳輸是否存在問題。然后從軟件層面,是否因為緩沖區太小丟包。

物理硬件方面

查看工作模式是否正常
ethtool eth0 | egrep 'Speed|Duplex'

查看檢驗是否正常
ethtool -S eth0 | grep crc

軟件層面overruns 和 buffer size

ethtool -g eth0
ethtool -G eth0 rx 2048
ethtool -G eth0 tx 2048

學習案例
http://blog.huoding.com/2020/04/27/814
https://blog.csdn.net/weixin_39630855/article/details/111265643?utm_medium=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-2.nonecase&depth_1-utm_source=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-2.nonecase


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM