壅塞與流量控制

緩衝膨脹(bufferbloat)

更大的候診室總是更好,這似乎很顯然——空間更多、被拒於門外的人更少。但想像一間有巨大候診室、卻只有一位慢吞吞醫生的診所:沒人被拒,可是每個人都要等上好幾個鐘頭。緩衝膨脹(bufferbloat)就是這個陷阱的網路版。記憶體變便宜了,於是設備廠商替路由器與數據機裝上巨大的封包緩衝區,以為這能防止遺失。結果,那些過大的緩衝區填滿後,反而替每個通過的封包加上龐大、持久的延遲。

原因是這樣的。一個基於遺失的 TCP 傳送端,像 CUBIC,會一直增大它的視窗,直到看見一個封包被丟。如果瓶頸處的緩衝區巨大,TCP 就會在任何封包被丟之前把整個緩衝區填滿——而滿載的緩衝區意味著現在每個封包都排在一條長隊裡,等著輪到自己。連結的吞吐量維持很高(管線是滿的),但延遲卻暴漲:一個本該 20 毫秒就穿越的封包,現在可能要花 300 毫秒,因為它有 280 毫秒花在排隊、等待前面積壓的封包。頻寬看起來沒問題;反應靈敏度卻被毀了。

緩衝膨脹正是為何只要同一條連線上有別人開始一個大下載,你的網頁就會感覺遲鈍、視訊通話會卡頓、線上遊戲會延遲——即使頻寬綽綽有餘。解法針對的是佇列,而非頻寬:主動佇列管理(CoDel 藉由監看封包停留多久來保持佇列短)、ECN(在不丟棄的情況下發出壅塞信號),以及像 BBR 這類基於模型的控制器(它刻意讓緩衝區保持清空)。教訓違反直覺卻關鍵:要低延遲,你要的是小而管理良好的緩衝區,而非大的。

你正在視訊通話,這時室友開始上傳一個巨大的檔案。上行的過大緩衝區被他的封包填滿,而你通話的小封包現在必須排在那堆積壓後面。你對路由器的閒置 ping 從 10 毫秒跳到 250 毫秒,你的聲音變得斷斷續續又遲到——然而速度測試仍回報完整的上傳頻寬。那道「頻寬沒問題、延遲卻被毀掉」的落差,就是緩衝膨脹。

一個過大、未受管理的緩衝區維持高吞吐量,卻加上巨大的佇列延遲——頻寬沒問題,延遲卻毀了。

緩衝膨脹是「更大的緩衝區並非更好」最清楚的證明。基於遺失的 TCP 會填滿它所遇到的任何緩衝區,所以一個過大的緩衝區只會轉化成延遲。解藥是更小、受主動管理的佇列(AQM 如 CoDel)加上 ECN 或基於模型的控制器——而非更多記憶體。

又称
buffer bloat緩衝膨脹緩衝區膨脹