多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php框架 > 框架設計 > linux內核工程導論-網絡:tcp擁塞控制——PRR

linux內核工程導論-網絡:tcp擁塞控制——PRR

來源:程序員人生   發布時間:2016-07-26 13:33:00 閱讀次數:6738次

Prr是rfc對快速回復算法的改進,實際的在linux中的實現是谷歌的哥們做的。這篇文章改編自網友的另外一篇很多英文的文章,為了我自己的理解,我就整理了1下。

快恢復是在檢測到堵塞產生的時候將發送窗口下降到1半(怎樣才算堵塞由另外的算法決定)。

PRR簡介

PRR是最新的linux的默許推薦堵塞算法,之前的是cubic。但是成心思的是,在linux中使用了prr依然可以以cubic作為默許堵塞算法。由于盡人皆知的,堵塞算法大致都是1樣的,只是在1些參數和細節調劑上有區分。Linux上的prr實現就是個對tcp_input.c文件的補充,其實不是以模塊的情勢提供的。

Prr是1個rfc的推薦標準,有推薦的實現方式。內核中對prr的實現是谷歌的1個工程師做的,也就是rfc中推薦的實現方式:PRR-SSRB

窗口機制的內核實現

傳輸數據的時候,如果發送方傳輸的數據量超過了接收方的處理能力,那末接收方會出現丟包。為了不出現此類問題,流量控制要求數據傳輸雙方在每次交互時聲明各自的接收窗口「rwnd」大小,用來表示自己最大能保存多少數據,這主要是針對接收方而言的,通俗點兒說就是讓發送方知道接收方能吃幾碗飯,如果窗口衰減到零,那末就說明吃飽了,必須消化消化,如果硬撐的話說不定會大小便失禁,那就是丟包了。

雖然流量控制可以免發送方過載接收方,但是卻沒法避免過載網絡,這是由于接收窗口「rwnd」只反應了服務器個體的情況,卻沒法反應網絡整體的情況。

為了不過載網絡的問題,慢啟動引入了堵塞窗口「cwnd」的概念,用來表示發送方在得到接收方確認前,最大允許傳輸的未經確認的數據。「cwnd」同「rwnd」相比不同的是:它只是發送方的1個內部參數,無需通知給接收方,其初始值常常比較小,然后隨著數據包被接收方確認,窗口成倍擴大,有點類似于拳擊比賽,開始時不了解敵情,常常是次拳摸索,漸漸心里有底了,開始逐步加大重拳進攻的力度。

發送方通過對「cwnd」大小的控制,能夠避免網絡過載,在此進程中,丟包與其說是1個網絡問題,倒不如說是1種反饋機制,通過它我們可以感知到產生了網絡堵塞,進而調劑數據傳輸策略,實際上,這里還有1個慢啟動閾值「ssthresh」的概念,如果「cwnd」小于「ssthresh」,那末表示在慢啟動階段;如果「cwnd」大于「ssthresh」,那末表示在堵塞避免階段,此時「cwnd」不再像慢啟動階段那樣呈指數級整整,而是趨向于線性增長,以期避免網絡堵塞,此階段有多種算法實現。

rwnd對應著內核的接收緩存大小,例如net.ipv4.tcp_rmem就能夠很大程度上控制rwnd,它表示的是接收方的物理接收能力。很多tcp性能的瓶頸就產生在這里。

堵塞時發送窗口的變化

堵塞算法實際作用的是cwnd,傳統的方法在發送的時候產生堵塞的時候,會把cwnd設置為原來的1半(快速恢復),在linux原來的實現中,這個值被設置為packets_in_flight + 1。在這類情況下,想象1個場景。1個http要求在發送的時候產生了快速恢復。由于cwnd迅速變成原來的1半,所以能發送的數據快速變少,packets_in_flight + 1的值也就迅速變小,而每次收到ack的時候,內核都會把cwnd設置為packets_in_flight + 1。待1次http要求發送完,cwnd就會變的很小。后面再使用這個連接發送數據的時候就得面對1個很小的發送窗口了,也就是1個慢啟動進程,而實際上沒有這么小。Ppr的目的就是在1次http請發送完即便產生堵塞,cwnd的值接近于ssthresh的慢啟動門限,而不是接近0的滿啟動。

舊的快速恢復算法有RFC3517中定義的和linux中實現的速率減半方案,也就是說linux中實現的與rfc是不1樣的。Linux之所以不采取rfc中定義的方案也是由于rfc的方案可能在高丟包率的情況下發送太多的數據。而linux的方案也有問題就是可以致使比較長的恢復時間或過量重傳。

Rfc中定義的快速恢復方法

1、定義

進入恢復時

// cwnd和ssthresh都設置為已發送沒有接收到ack的數據包數目的1半

cwnd = ssthresh = FlightSize / 2

// 然后使用快速重傳機制重發第1個沒有收到ack的數據包

fast_retransmit()

// 如果cwnd還允許的話就發送更多

Transmit MAX(0, cwnd - pipe)

對恢復時收到的每一個數據包:

update_scoreboard() pipe = (RFC 3517 pipe algorithm)

Transmit MAX(0, cwnd - pipe)

2、 缺點

 Rfc的算法有時太過激進,有時太過守舊。

1. 半RTT安靜(守舊方面)

快速重傳機制在發現堵塞的時候,會進行第1次的重傳,rfc規定在快速重傳算法的重傳以后要等待網絡中flight(已發出但是沒有收到ack)數據包的1半的ack收到以后才能繼續發送數據。而很多情況下,這個等待是無意義的,快速重傳變成了慢速重傳。

 

2. 高強度的突發重傳(激進方面)

由于rfc的算法在快速重傳以后接收到1個ack以后可以大量的突發發送數據(取決于設計的管道流),而這類突發在真實的產生了網絡堵塞時候會造成更嚴重的網絡丟包。而根據標準,產生的丟包越嚴重,突發發送的時候產生的突發量越大,也就越加重這個丟包。這類模式在http網頁和是頻率中有都有不好的表現。

Linux中實現的快速恢復方法

由于rfc的問題,linux做了優化。快速恢復時不時等待收到ack以后才繼續發送數據,而是只要進入快速恢復就依然繼續發送數據,但是發送數據的窗口立即下降為原來窗口的1半。這樣就避免了半RTT安靜問題和減緩了突發重傳的問題。

但是同時帶來了1個問題,就是如果確切是產生了發送的網絡堵塞,發送窗口會快速下降,1方面壓抑了自己向網絡中發送數據的速度(看起來是對的),但是1方面也把自己的后續發送數據的能力下降到慢開始的級別。

也就是在1種業務場景產生時,這個算法會把自己置于慢開始的地步。這個場景就是當產生堵塞時,不是由于網絡緣由致使發送量減少,而是由于利用程序的緣由致使的。此時cwnd會延續的減小,即便網絡沒有產生堵塞。由于cwnd是不是減小是由發送的速度決定的,而此時發送速度又是由利用程序決定的。并且當cwnd降落到ssthresh以下的時候,linux的發送策略就變成必須遭到1個ack發能發送1個數據包,此時又進1步加重了此tcp管道的性能惡化。

所以就會出現tcp的效力非正確的快速降落。

PPR_SSRB方法

原來的算法主要有兩個問題:產生堵塞的時候發送窗口快速降落,降落速度過快;降落的最下限是cwnd1,低于慢開始閾值,致使后續的數據包會從慢開始進程開始。SSRB針對性讓降落的最小值為ssthresh(慢開始門限),并且發送速度逐漸緩慢降落,并且這個降落是根據實時的網絡情況肯定的,不是估計的。

 

網絡中每N個包退出(被接收端緩存了),則發送beta * N個包(重傳或新的)。

網絡中數據包守恒的情況:

sndcnt = prr_delivered - prr_out; /* 11的兌換關系*/

網絡中數據包按比例減少:

sndcnt = (snd_sshresh / prior_cwnd) * prr_delivered - prr_out; /* 1/beta1的兌換關系*/

舉例來講,使用cubic算法,beta0.7。如果有10個包被接收或緩存了(退出網絡了),則可以發送7個包(重傳或新的),

這樣1來,網絡中存在的數據包就減少了3個,在全部快速恢復的進程中,網絡中存在的數據量逐步減少為初始的0.7

這就是所謂的按比例減小,減小的比例即為30%

                 <-------------------------N--------------------------

Server                                                                                          Client

                 ----------------0.7 * N----------------->

實際上是在用prr_deliveredprr_out來實時丈量網絡中存在的數據段個數(所以說更加準確,由于這不是猜想)。

這是1個漸變的進程,不斷兌換的進程,終究網絡中存在的數據量和堵塞窗口都收斂于snd_ssthresh

這個算法的核心是利用Van Jacobson的數據包守恒定理:發送到網絡中的數據包數量是發送數據包的控制時鐘。

 

算法分為兩部份:1部份是堵塞發送降落的時候采取sndcnt = (snd_sshresh / prior_cwnd) * prr_delivered - prr_out;的公式降落。其中prr_delivered是收到接收方的ack,表示已被接收方從網絡中拿走的部份,prr_out是尚在網絡中的部份。此公式保證了發送的速度與接收的速度成正比,由于系數的存在(不同的算法可以設置不同的系數),使得系數在cwnd不斷接近sshresh的時候,系數逐步變成1,在堵塞剛開始的時候系數還是比較大的,所以這個發送數據包降落的進程是先快后慢的,直到到達ssthresh,發送速率穩定。所以終究的窗口會收斂到ssthresh。第2部份是當cwnd1旦降落到ssthresh以下的時候(正常情況不會,但是如果利用程序中斷了數據傳輸,prr_out0,cwnd也會逐步降落到0,與rfc1樣),此時另外1個配套機制啟動,就是當快重傳階段cwnd掉到ssthresh以下時,啟動慢啟動機制,讓cwnd的量慢速上升。

通過這兩個部份算法的配合就能夠完成全部PRR_SSRB算法。

PPR_SSRB的改動

 

 PPR_SSRB的改動包括在tcp_sock上添加了幾個域:

 

1. struct tcp_sock {  

2.     ...  

3.     /* Congestion window at start of Recovery. 進入Recovery前的堵塞窗口*/  

4.     u32 prior_cwnd;       

5.   

6.     /* Number of newly delivered packets to receiver in Recovery. 

7.      * 實際上用于統計data_rate_at_the_receiver,數據離開網絡的速度。 

8.       */  

9.     u32 prr_delivered;   

10.   

11.     /* Total number of pkts sent during Recovery.  

12.      * 實際上用于統計sending_rate,數據進入網絡的速度。 

13.       */  

14.     u32 prr_out;      

15.     ...  

16. }   

@net/ipv4/tcp_input.c

 

1. static inline void tcp_complete_cwr (struct sock *sk)  

2. {  

3.     struct tcp_sock *tp = tcp_sk(sk);  

4.     /* Do not moderate cwnd if it's already undone in cwr or recovery. */  

5.     if (tp->undo_marker) {  

6.         if (inet_csk(sk)->icsk_ca_state == TCP_CA_CWR)  

7.             tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);  

8.   

9.         else /* PRR */  

10.             tp->snd_cwnd = tp->snd_ssthresh; /* 避免沒必要要的進入慢啟動*/  

11.   

12.         tp->snd_cwnd_stamp = tcp_time_stamp;  

13.     }  

14.     tcp_ca_event(sk, CA_EVENT_COMPLETE_CWR);  

15. }  

[java] view plain copy

1. /* This function implements the PRR algorithm, specifically the PRR-SSRB 

2.  * (proportional rate reduction with slow start reduction bound) as described in 

3.  * http://www.ietf.org/id/draft-mathis-tcpm-proportional-rate-reduction-01.txt. 

4.  * It computes the number of packets to send (sndcnt) based on packets newly 

5.  * delivered: 

6.  *    1) If the packets in flight is larger than ssthresh, PRR spreads the cwnd 

7.  *         reductions across a full RTT. 

8.  *    2) If packets in flight is lower than ssthresh (such as due to excess losses 

9.  *         and/or application stalls), do not perform any further cwnd reductions, but 

10.  *         instead slow start up to ssthresh. 

11.  */  

12.   

13. static void tcp_update_cwnd_in_recovery (struct sock *sk, int newly_acked_sacked,  

14.                 int fast_rexmits, int flag)  

15. {  

16.     struct tcp_sock *tp = tcp_sk(sk);  

17.     int sndcnt = 0/* 對每一個ACK,可以發送的數據量*/  

18.     int delta = tp->snd_ssthresh - tcp_packets_in_flight(tp);  

19.   

20.     if (tcp_packets_in_flight(tp) > tp->snd_ssthresh) {  

21.   

22.         /* Main idea : sending_rate = CC_reduction_factor * data_rate_at_the_receiver, 

23.           * 依照堵塞算法得到的減小因子,按比例的減小pipe,終究使pipe收斂于snd_ssthresh。 

24.           */  

25.         u64 dividend = (u64) tp->snd_ssthresh * tp->prr_delivered + tp->prior_cwnd - 1;  

26.         sndcnt = div_u64(dividend, tp->prior_cwnd) - tp->prr_out;  

27.   

28.     } else {  

29.         /* tp->prr_delivered - tp->prr_out首先用于撤消之前對pipe的減小,即首先讓網絡中的數據包恢復守恒。 

30.          * 然后,tp->prr_delivered < tp->prr_out,由于目前是慢啟動,網絡中數據包開始增加: 

31.          * 對每一個ACK,sndcnt = newly_acked_sacked + 1,使pipe加1,即慢啟動。 

32.          * delta使pipe終究收斂于snd_ssthresh。 

33.          */  

34.         sndcnt = min_t(int, delta, max_t(int, tp->prr_delivered - tp->prr_out, newly_acked_sacked) + 1);  

35.     }  

36.   

37.     sndcnt = max(sndcnt, (fast_rexmit ? 1 : 0));  

38.     tp->snd_cwnd = tcp_packets_in_flight(tp) + sndcnt;  

39. }  

@tcp_ack()

[java] view plain copy

1. /* count the number of new bytes that the current acknowledgement indicates have 

2.  * been delivered to the receiver. 

3.  * newly_acked_sacked = delta(snd.una) + delat(SACKed) 

4.  */  

5. newly_acked_sacked = (prior_packets - tp->packets_out) + (tp->sacked_out - prior_sacked);  

6.   

7. ...  

8.   

9. tcp_fastretrans_alert(sk, prior_packets - tp->packets_out, newly_acked_sacked, flag);  

 

 


生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 欧美一区二区三区在观看 | 精品视频在线观看一区二区三区 | 日韩欧美精品在线观看 | 免费在线亚洲视频 | 国产v综合v亚洲欧美大另类 | 国产三级日产三级 | 日本一区二区视频在线观看 | 亚洲国产成人资源在线桃色 | 中文字幕在线视频播放 | 精品一区精品二区 | 亚洲日本一区二区三区 | 在线观看免费xx高清视频 | 久久一区二区三区四区 | 一级日本特黄毛片视频 | 18在线网站 | 久草干| 久久婷婷人人澡人人爱91 | 国产香蕉在线精彩视频 | 伊人亚洲综合网成人 | 久久久久国产精品免费 | 性久久久久久久 | jizzjizzjizz18中国 | 亚欧成人毛片一区二区三区四区 | 日本高清中文字幕一区二区三区 | 色就色欧美综合偷拍区a | 色综合欧美亚洲另类久久 | 沈樵在线观看福利 | 亚洲福利精品一区二区三区 | 最近中文字幕2019年免费 | 欧美jizzhd精品欧美另类 | 亚洲最大色图 | 欧美精品一区二区三区久久 | 国产精品视频第一区二区三区 | 精品国产一区二区三区免费看 | 日本中文字幕在线视频 | 伊人色婷婷 | 亚洲视频在线观看免费 | 12306播播影视播播影院午夜 | 欧美成综合网网站 | 欧美一级欧美三级在线观看 | 欧美黑人极品hdxxx |