BBR 的 buffer 動力學觀感

這周很忙,今天還加了一天班,但還是抽空實現了五一在安徽涇縣山區喝著一壺酒寫的 BBR ProbeRTT 的想法,沒多少行代碼,它真就消除了帶寬鋸齒,皮了個鞋👞,昨天我還在群里說了今天再說說 BBR 的,回到家就作圖作文了。

去年夏天,我花了些精力量化 BBR 動力學,并給出一些相圖以及收斂方程的數值解,但數學也只是描述而非解釋,就像牛頓定律只能描述萬有引力卻無法解釋引力的由來(任何理論都無法解釋)一樣。所以這個話題要不斷推敲,常看常新,搞不好就有新思路了。

BBR 動力學核心是收斂,歸為一句話就是 “帶寬越大 Probe 加速比越小”,這句話是收斂的原因,進一步通俗解釋,大的想更大更難,是為邊際收益遞減,小的想更大也難,但邊際收益單調遞減,卻仍高于大的,相對而言其加速比就更大。buffer 動力學解釋,即小流 Probe 的結果比大流的更大,大流就表現出凈損而讓給小流了。

《道德經》里早有論述,“天之道,損有余而補不足”,看來這是天道,容不得解釋。而 “人之道則不然,損不足以奉有余”,則與《新約 · 馬太福音》相呼應了。

我也常常提到 “矩”,它是一個乘積,與一個值不同的是,它體現了兩個維度的膠合,兩個維度的矩針對一個維度的值,其結果就是邊際收益遞減了,因為兩個維度的伸縮比例并不常一致,所謂矩的效應,就比如面積相同而周長不等,或周長相同而面積各異,正如力和力臂,矩不變,但費料不同。

套用解釋 buffer 動力學,BDP 就是擠出帶寬的矩,BBR 靠 1.25 倍增益來體現邊際收益遞減,直到當它繼續再減下去時,對方也要跟著減下去,這時候收斂到公平,方可停止,驚奇的是,這件事確實自然發生。

5 月 2 日晚,我在安徽宣城寫了一篇 BBR ProbeRTT 新改,提出一個新思路,近日測試,是那么回事。我大致說的是,BBR 一定需要借宿于 buffer 中收斂到公平,為守其初衷,卻又要 ProbeRTT,但原生 ProbeRTT 的假設太苛刻,對全局同步過度依賴,這境況在強弱不等的持續統計波動中未必能保持,何不哺其糟而歠其醨,將自己因 Probe 而建立的 queue 吐出即可。

我模仿 Jaffe’s style,用四則混合運算描述 BBR buffer 動力學,基于表達式推出一個結論,基于該結論給出上述 ProbeRTT 描述,即刻取消 BBR 由于 ProbeRTT 導致的邪惡帶寬鋸齒(BBR 終于擺脫了 cwnd 鋸齒,卻為何還要面對 bw 鋸齒)。

設總帶寬為 1,流 1 帶寬為 x,則流 2 帶寬則為 1 - x,以 ProbeBW 之 ProbeUP phase 論,流 1 和流 1 的帶寬增量表示為:

f 1 ( x ) = g ? x g ? x + 1 ? x ? x x + 1 ? x f_1(x)=\dfrac{\mathrm{g}\cdot x}{\mathrm{g}\cdot x+1-x}-\dfrac{x}{x+1-x} f1?(x)=g?x+1?xg?x??x+1?xx?

f 2 ( x ) = g ? ( 1 ? x ) g ? ( 1 ? x ) + x ? ( 1 ? x ) ( 1 ? x ) + x f_2(x)=\dfrac{\mathrm{g}\cdot (1-x)}{\mathrm{g}\cdot (1-x)+x}-\dfrac{(1-x)}{(1-x)+x} f2?(x)=g?(1?x)+xg?(1?x)??(1?x)+x(1?x)?

不必化簡,直接畫圖:
在這里插入圖片描述

最下面灰線是 f1(x) - f2(x),可清晰看出 x = 0.5 的分水嶺,當 x < 0.5,f1(x) 屬小流帶寬演進,f2(x) 屬大流帶寬演進,小流擠壓大流帶寬,反之亦然。

這也不難直觀理解,以 AIMD 為例,當 x,y 分別為兩流不同的初始 cwnd 時,設 x < y,那么 x + L y + L \dfrac{x+L}{y+L} y+Lx+L? 當 L 越大,值越趨向 1 收斂到公平,即只要 additive increase 一直持續,總會收斂,BBR 同樣,每次 Probe 都會堆一小丟丟 queue,大流堆的少,小流堆得更多些, x + L b i g g e r y + L s m a l l e r \dfrac{x+L_{bigger}}{y+L_{smaller}} y+Lsmaller?x+Lbigger?? 看起來要比 AIMD 更快趨向 1,但 L 都超級小(如圖所示,我還特意縮放了坐標比例),總體上還是 AIMD 應有的收斂速度。

f1(x),f2(x) 顯然關于 x = 0.5 對稱,它們之做差結果顯示了 “損有余而補不足” 的過程,該過程強度逐漸收緩(如圖綠藍線之間的間隙),直至兩者再無差異,它們與 x = 0.5 相交的此點即穩定點,它是不動點。

依照上述 5 月 2 日的 ProbeRTT 方法,釋放自己堆積的 queue,在上圖的意義就是分別求綠線 x 到 0.5 以及藍線 0.5 到 1 - x 的積分,肉眼觀測,面積是相等的,大差不差一個相位。

現在演示一下實際上是不是這樣:

import numpy as np
import matplotlib.pyplot as plt
import randomx0 = 0.2  
y0 = 0.8 
g = 1.25  
bx, by = 0, 0
R = 2
C = 1num_steps = 500
t = np.arange(num_steps)  # 帶寬
x = np.zeros(num_steps)
y = np.zeros(num_steps)
# BDP
Bx = np.zeros(num_steps)
By = np.zeros(num_steps)
# RTwait
r = np.zeros(num_steps)
# 自己堆占的 queue
Ax = np.zeros(num_steps)
Ay = np.zeros(num_steps)
# 自己堆棧 queue 的平均
sAx = np.zeros(num_steps)
sAy = np.zeros(num_steps)x[0] = x0
y[0] = y0
r[0] = 0Bx[0], By[0] = x0, y0
Ax[0], Ay[0], sAx[0], sAy[0] = 0, 0, 0, 0
nx, ny = random.randint(5, 15), random.randint(5, 15)for i in range(1, num_steps):if i > 150:C = 5if i > 350:C = 0.2dec = 0x[i] = C * (g * x[i-1]) / (g * x[i-1] + y[i-1]) tx = C * x[i-1] / (x[i-1] + y[i-1])bx += R * (x[i] - tx)if i % nx == 0: # x 隨意 ProbeRTT,不再依賴同步dec += bxbx = 0      # 退掉自己 Probe 造成的 queue,堆多少退多少nx = random.randint(5, 15)Ax[i] = bxsAx[i] = 0.9 * sAx[i-1] + 0.1 * bx#y[i-1] = C - x[i]   # 忘記 max-filter bwy[i] = C * (g * y[i-1]) / (g * y[i-1] + x[i])  ty = C * y[i-1]/(y[i-1] + x[i])by += R * (y[i] - ty)if i % ny == 0: # y 隨意 ProbeRTT,不再依賴同步dec += byby = 0      # 退掉自己 Probe 造成的 queue,堆多少退多少ny = random.randint(5, 15)Ay[i] = bysAy[i] = 0.9 * sAy[i-1] + 0.1 * by#x[i] = C - y[i]  # 忘記 max-filter bwr[i] = (((x[i] + y[i]) * R) + bx + by- dec) / C - Rif r[i] < 0:r[i] = 0Bx[i] = r[i] * x[i]By[i] = r[i] * y[i]fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(8, 6))ax1.plot(t, r, label='rtt(t)', color='green')ax1.plot(t, x, label='bw_x(t)', linestyle=':', color='blue')
ax1.plot(t, y, label='bw_y(t)', linestyle=':', color='red')
ax2.plot(t, Bx, label='bdp_x(t)', linestyle=':')
ax2.plot(t, By, label='bdp_y(t)', linestyle=':')
ax3.plot(t, Ax, label='buf_x(t)', linestyle=':')
ax3.plot(t, Ay, label='buf_y(t)', linestyle=':')
ax3.plot(t, sAx, label='avg_buf_x(t)', linestyle='-')
ax3.plot(t, sAy, label='avg_buf_y(t)', linestyle='-')
ax1.set_xlabel('t')
ax1.set_ylabel('v')
ax2.set_xlabel('t')
ax2.set_ylabel('BDP')
ax2.set_xlabel('t')
ax2.set_ylabel('total buffer')
ax1.legend()
ax1.grid(True)
ax2.legend()
ax2.grid(True)
ax3.legend()
ax3.grid(True)
plt.show()

給出幾個結局:
在這里插入圖片描述

觀測到的現象是:

  • total buffer 寫錯了,應該去掉,因為已經有了圖例;
  • RTT 總體在一個很小范圍內波動,視 ProbeRTT 平均期望窗口而定,窗口越大,RTT 振幅越大;
  • bw,BDP,自己堆積 queue 總體都屬于統計公平狀態;
  • BDP 隨總帶寬 C 而漲跌,但整體非常公平;

這才像個真實的樣子,沒有任何假設和約束,但卻收斂到了公平。

但這里有個 BBR 細節,“為什么要在一個 max-filter bw 窗口內至少進入 Probe phase 一次”,比如 10-round 的 max-filter bw 窗口,要設計 8-round 的 ProbeBW cycle。如果將上述 python 代碼的兩行 “忘記 max-filter bw” 注釋放開,結局如下:
在這里插入圖片描述

這個結果寫出遞推式就能看明白,完全不必分析不動點和相圖。

最后,給出完全由 buffer 動力學驅動而不是照著 “算法” 臨摹的實際效果。還是先給出仿真代碼:

for i in range(1, num_steps):if i > 150:C = 5if i > 350:C = 0.2dec = 0# 根據 buffer 占比求帶寬x[i] = C * (g * x[i-1] * R) / (g * x[i-1] * R + y[i-1] * (r[i-1] + R)) # 如果不 probe 的帶寬tx = C * x[i-1] * (r[i-1] + R) / (x[i-1] * (r[i-1] + R) + y[i-1] * (r[i-1] + R))bx += R * (x[i] - tx)# 隨機而生的 ProbeRTT,不依賴同步if i % nx == 0:dec += bxbx = 0nx = random.randint(5, 15)# 即時 bufferAx[i] = bx# 即時 buffer 移動指數平均sAx[i] = 0.9 * sAx[i-1] + 0.1 * bx# 同 x,略y[i] = C * (g * y[i-1] * R) / (g * y[i-1] * R + x[i] * (r[i-1] + R))  ty = C * y[i-1] * (r[i-1] + R)/(y[i-1] * (r[i-1] + R) + x[i] * (r[i-1] + R))by += R * (y[i] - ty)if i % ny == 0:dec += byby = 0ny = random.randint(5, 15)Ay[i] = bysAy[i] = 0.9 * sAy[i-1] + 0.1 * by# RTwait = total_bdp / C - RTpropr[i] = (((x[i] + y[i]) * R) + bx + by- dec) / C - Rif r[i] < 0:r[i] = 0Bx[i] = r[i] * x[i]By[i] = r[i] * y[i]

以下幾個例子的實際采樣結局:
在這里插入圖片描述

真正的統計律主導,不以精確而以統計應對時局,可以看出 queue 以一個非常有限的振幅波動,沒有完全消除,但也不過度增加,且 ProbeRTT 也不再需同步,任意時刻執行均可(在一個最大窗口比如 5~10s 的約束內),它完全通過 buffer 動力學驅動。整體而言,這達到了一個松散的統計公平。

浙江溫州皮鞋濕,下雨進水不會胖。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/83523.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/83523.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/83523.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第9講、深入理解Scaled Dot-Product Attention

Scaled Dot-Product Attention是Transformer架構的核心組件&#xff0c;也是現代深度學習中最重要的注意力機制之一。本文將從原理、實現和應用三個方面深入剖析這一機制。 1. 基本原理 Scaled Dot-Product Attention的本質是一種加權求和機制&#xff0c;通過計算查詢(Query…

el-tree結合checkbox實現數據回顯

組件代碼 <el-tree:data"vertiList"show-checkboxnode-key"id":props"defaultProps"ref"treeRefx"class"custom-tree"check-change"handleCheckChange"> </el-tree>獲取選擇的節點 handleCheckChan…

OpenResty 深度解析:構建高性能 Web 服務的終極方案

引言 openresty是什么&#xff1f;在我個人對它的理解來看相當于嵌入了lua的nginx; 我們在nginx中嵌入lua是為了不需要再重新編譯,我們只需要重新修改lua腳本,隨后重啟即可; 一.lua指令序列 我們分別從初始化階段&#xff0c;重寫/訪問階段&#xff0c;內容階段&#xff0c;日志…

多商戶商城系統源碼解析:開發直播電商APP的技術底層實戰詳解

隨著直播電商的火爆&#xff0c;越來越多的創業者和企業都在尋求打造自己的多商戶商城系統&#xff0c;以實現“人、貨、場”三者的深度融合。然而&#xff0c;從一個簡單的電商平臺到一個功能完善的直播電商APP&#xff0c;其技術底層架構和實現過程并非一蹴而就。本文將從架構…

桌面端進程通信

以下是關于 Electron 桌面端進程通信的基本知識點總結: 一、Electron 進程模型基礎 1. 進程類型與職責 進程類型職責權限主進程(Main)創建窗口、系統級操作、IPC中樞完全Node.js訪問權限渲染進程(Renderer)展示Web內容、UI交互默認受限(可配置開啟Node.js)預加載腳本(Prelo…

openEuler24.03 LTS下安裝MySQL8.0.42

目錄 前提步驟 刪除原有mysql及maridb數據庫 安裝MySQL 啟動MySQL 啟動查看MySQL狀態 設置MySQL開機自啟動 查看登錄密碼 登錄MySQL 修改密碼及支持遠程連接 遠程連接MySQL 前提步驟 擁有openEuler24.03 LTS環境&#xff0c;可參考&#xff1a;Vmware下安裝openEule…

idea 保證舊版本配置的同時,如何從低版本升到高版本

文章目錄 前言idea 保證舊版本配置的同時,如何從低版本升到高版本1. 備份項目2. 下載最新的idea3. 安裝安裝包4. 導入idea2019舊配置5. 驗證前言 如果您覺得有用的話,記得給博主點個贊,評論,收藏一鍵三連啊,寫作不易啊^ _ ^。 ??而且聽說點贊的人每天的運氣都不會太差,…

填坑記: 古董項目Apache POI 依賴異常排除

當你看到NoSuchMethodError的時候&#xff0c;不要慌&#xff0c;深呼吸&#xff0c;這可能只是JAR包版本的問題… 引子&#xff1a;一個平靜的周二下午 那是一個看似平常的周二下午&#xff0c;系統運行良好&#xff0c;開發團隊在有條不紊地推進著新功能的開發。突然&#x…

CAPL Class: TcpSocket (此類用于實現 TCP 網絡通信 )

目錄 Class: TcpSocketacceptopenclosebindconnectgetLastSocketErrorgetLastSocketErrorAsStringlistenreceivesendsetSocketOptionshutdown函數調用的基本流程服務器端的基本流程客戶端的基本流程Class: TcpSocket學習筆記。來自CANoe幫助文檔。 Class: TcpSocket accept /…

微信小程序的開發及問題解決

HttpClient 測試例子 SpringBootTest public class HttpClientTest {/*** 測試通過httpclient發送get方式的請求*/Testpublic void testGET() throws IOException {//創建httpclient對象CloseableHttpClient httpClient HttpClients.createDefault();//創建請求對象HttpGet ht…

foreach中使用await的問題

目錄 1.說明 2.示例 3.解決方案 1.說明 在foreach中調用異步方法&#xff0c;即使使用了await&#xff0c;不會依次執行每個異步任務&#xff0c;也就是說Array.prototype.forEach不會等待 Promise 完成&#xff0c;即使你在回調函數中返回一個 Promise&#xff0c;forEach …

Linux調試生成核心存儲文件

1.核心存儲文件配置&#xff1a; 不知道理解對不對&#xff0c;Linux中的核心存儲文件的配置是在/proc/sys/kernel/core_pattern中的&#xff0c;使用 cat /proc/sys/kernel/core_pattern # 打印出 |/usr/share/apport/apport -p%p -s%s -c%c -d%d -P%P -u%u -g%g -- %E表示核…

Compose筆記(二十三)--多點觸控

這一節主要了解一下Compose中多點觸控&#xff0c;在Jetpack Compose 中&#xff0c;多點觸控處理需要結合Modifier和手勢API來實現&#xff0c;一般通過組合 pointerInput、TransformableState 和 TransformModifier 來創建支持縮放、旋轉和平移的組件。 一、 API 1. Pointer…

【Java ee初階】HTTP(4)

構造HTTP請求 1&#xff09;開發中&#xff0c;前后端交互。瀏覽器運行的網頁中&#xff0c;構造出HTTP請求 2&#xff09;調試階段&#xff0c;通過構造HTTP請求測試服務器 樸素的方案&#xff1a; 通過tcp socket 的方式構造HTTP請求 按照HTTP請求格式&#xff0c;往TCP…

STM32 __main

STM32開發中__main與用戶main()函數的本質區別及工作機制 在STM32開發中&#xff0c;__main和用戶定義的main()函數是啟動過程中的兩個關鍵節點&#xff0c;分別承擔運行時初始化和用戶程序入口的職責。以下是它們的核心差異及協作機制&#xff1a; 一、定義與層級差異 ?__ma…

什么是PMBus

一、PMBus的定義與背景 PMBus&#xff08;Power Management Bus&#xff0c;電源管理總線&#xff09; 是一種基于SMBus&#xff08;System Management Bus&#xff09;的開放標準數字通信協議&#xff0c;專為電源設備的監控、配置和控制設計。由PMBus聯盟&#xff08;現并入…

Python OOP核心技巧:如何正確選擇實例方法、類方法和靜態方法

Python方法類型全解析&#xff1a;實例方法、類方法與靜態方法的使用場景 一、三種方法的基本區別二、訪問能力對比表三、何時使用實例方法使用實例方法的核心場景&#xff1a;具體應用場景&#xff1a;1. 操作實例屬性2. 對象間交互3. 實現特定實例的行為 四、何時使用類方法使…

業務中臺-典型技術棧選型(微服務、容器編排、分布式數據庫、消息隊列、服務監控、低代碼等)

在企業數字化中臺建設中&#xff0c;業務中臺是核心支撐平臺&#xff0c;旨在通過技術手段將企業核心業務能力抽象、標準化和復用&#xff0c;以快速響應前端業務需求。其核心技術流涉及從業務抽象到服務化、治理和持續優化的全流程。以下是業務中臺建設中的核心技術體系及關鍵…

期望是什么:(無數次的均值,結合概率)21/6=3.5

https://seeing-theory.brown.edu/basic-probability/cn.html 期望是什么:(無數次的均值,結合概率)21/6=3.5 一、期望(數學概念) 在概率論和統計學中,**期望(Expectation)**是一個核心概念,用于描述隨機變量的長期平均取值,反映隨機變量取值的集中趨勢。 (一…

matlab官方免費下載安裝超詳細教程2025最新matlab安裝教程(MATLAB R2024b)

文章目錄 準備工作MATLAB R2024b 安裝包獲取詳細安裝步驟1. 文件準備2. 啟動安裝程序3. 配置安裝選項4. 選擇許可證文件5. 設置安裝位置6. 選擇組件7. 開始安裝8. 完成輔助設置 常見問題解決啟動失敗問題 結語 準備工作 本教程將幫助你快速掌握MATLAB R2024b的安裝技巧&#x…