JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

TCP Incast 與資料中心壅塞控制

那個在開放網際網路上小心翼翼開車、馴服流量的 TCP,一進到資料中心裡卻會崩潰:幾十台伺服器在同一個毫秒內回答同一個請求,把交換器那一丁點緩衝區擠爆。本篇說明為何經典壅塞控制在這種時間尺度上會失靈,以及 DCTCP 如何在「看到一絲絲排隊跡象」時就先踩煞車,而不是乾等到撞車。

一張快到讓 TCP 犯糊塗的網路

到現在,你已經逛過雲端的內部:那張資料中心網路、它在伺服器之間奔流的 東西向流量、那個給任意兩台機器一條又胖又低延遲路徑的葉脊架構,以及把眾多流量分散到許多等價鏈路上的 ECMP。這一切工程的全部目的,就是讓網路快到燙手——單一棟建築物內的來回時間是以「幾十微秒」計,而不是你在網際網路上看到的「幾十毫秒」。你或許會預期:網路愈快,TCP 只會愈開心。本篇令人意外的真相卻相反:資料中心的「快」與「形狀」本身,打破了普通 TCP 賴以建立的假設,於是一個在開放網際網路上表現得無比優雅的傳輸協定,在這裡卻會散架。

回想傳輸那一級裡,經典壅塞控制的心智模型:TCP 是個小心的駕駛,輕輕加速、用力煞車。它沒有量網路的「時速表」,只能靠感覺學路——它不斷放大自己的壅塞視窗(每一回合多送一點),直到丟了一個封包,就把這次丟失當成「我推得太用力了」的訊號,猛地把視窗踩下來。在廣大的網際網路上這行得通,因為丟一個封包確實意味著某處某個路由器佇列滿溢,而且一次來回夠長,駕駛有時間反應。可是在資料中心內部,這兩個慰藉都消失了:來回短到幾乎沒時間反應,而交換器緩衝區小到「丟失」是以猛烈的、一次全來的爆量形式抵達,而不是一個溫和的警告。

Incast:當所有人同時回話

下面就是那個會把事情搞砸的型態,而它直接從你已認識的東西向流量裡掉出來。許多資料中心的工作是「散開—收攏」式的:一台機器問一個被切分到幾十、幾百台伺服器上的問題——「從四十個分片讀這一列」、「從一百台索引伺服器抓這些搜尋結果」——而那每一台伺服器幾乎在同一瞬間回話,因為請求是一起抵達它們的。所有這些回覆,都匯聚到那條通回「唯一那個請求者」的單一鏈路上。這場同步湧向一個共用瓶頸的洪水,就是 TCP incast:多個發送者、一個接收者,全在同一瞬間抵達。

Scatter-gather -> incast at the last-hop switch

  worker 1 --\
  worker 2 ---\
  worker 3 ----\   (all reply in the SAME millisecond)
   ...          >===[ switch port buffer ]===> aggregator
  worker 39 ---/        ^ tiny: fills in microseconds
  worker 40 --/         -> overflows -> packets DROPPED

  Dropped TCP segments wait for a retransmission timeout (RTO).
  Datacenter RTT ~ 100 us, but a default minimum RTO ~ 200 ms.
  One unlucky flow stalls 200,000 us to recover a 100 us trip.
四十個工人同時回答同一個請求;它們的回覆堆進同一個交換器連接埠,那緩衝區在幾微秒內填滿並滿溢。被丟掉的區段無法被快速察覺,於是受害的那條流量得乾等一個重傳逾時——而這逾時把來回時間整整放大了一千倍。

現在那些小小的數字變得殘酷了。那台末跳交換器連接埠上的緩衝區在幾微秒內滿溢,幾個同步回覆就這樣被丟掉。一個被丟掉的 TCP 區段,通常會被快速重傳救回來——但快速重傳需要幾個後續封包抵達、觸發重複確認,而在一陣緊湊的 incast 爆量裡,發送者手上可能根本沒有別的在途封包來觸發它們。於是這條流量退回它的安全網:重傳逾時。陷阱很殘忍:這個逾時有個下限,歷史上大約是 200 毫秒,而資料中心的來回大約是 100 微秒。為了從「丟掉一趟 100 微秒的旅程」中恢復,連線竟停滯了二十萬微秒。少數幾條倒霉的流量乾坐在逾時上,就能把整個散開—收攏請求拖到龜速。

要精確地說「失敗的是什麼」,因為這其實並不是 TCP 錯了。TCP 那條「丟失等於壅塞」的規則、以及它的逾時,在網際網路上都完全合理;它們只是假設「丟失偶爾發生」且「來回很長」。Incast 一次違反了這兩個假設。人們最先伸手去抓的修法都很窄:把那個最小逾時縮到微秒級,好讓停滯的流量快速恢復;或者讓回覆別這麼完美地同步。有用,但它們治的是症狀——洪水仍舊砸向一個會滿溢的緩衝區。更深的修法,是讓緩衝區一開始就別滿溢,這意味著要改變壅塞訊號本身。

微爆量:在圖表上看不見的麻煩

Incast 是一種更普遍的資料中心病症的成因之一:微爆量。微爆量是一陣短到只持續幾微秒的流量洪水,但在那幾微秒裡,它抵達的速度比交換器連接埠能排空的還快,於是緩衝區瞬間填滿、甚至可能滿溢。最叫人抓狂的是:它對普通監控是隱形的。一個「以一秒為單位平均」回報使用率的交換器計數器,可能讀到舒舒服服的 30%,然而就在那一秒之內,一陣 50 微秒的爆量曾一度索求該連接埠 300% 的容量、並丟掉了封包。平均值很平靜;那個毫秒卻著了火。

這是資料中心版本的一個值得點名的迷思。在開放網際網路上你見過 緩衝區膨脹(bufferbloat)——緩衝區太大的問題,多餘的資料坐在一條肥肥的佇列裡,替所有人吹脹了延遲。在資料中心裡,危險卻偏向另一邊:緩衝區被刻意做小以壓低延遲,所以故障模式不是膨脹的佇列,而是突然的滿溢丟包。兩者共同的教訓是:一條佇列就是你選擇承擔的一份延遲,而真正的本事在於——把佇列保持得夠短以維持快速,卻又不至於短到一陣正常的爆量就溢出來。你想要的是:佇列幾乎永遠幾乎是空的。

DCTCP:在「跡象」上煞車,而非在「撞車」上

把這一切串起來的聰明點子,叫做 DCTCP,即 Data Center TCP(資料中心 TCP)。它的洞見一句話就能說完:別等到封包被丟掉才煞車——在佇列「開始」堆積、還有空間時就反應。為了拿到提早的警告,DCTCP 倚賴一個你在傳輸那一級見過的功能:顯式壅塞通知(ECN)。有了 ECN,一台看見自己佇列長過某個小門檻的交換器,不會把封包丟掉;它會在封包的標頭裡設一個標記位元,意思是「我快壅塞了」。封包仍然會抵達,接收者再把那個標記回傳給發送者。這下訊號變成了「懸崖前的溫和警告」,而不是「崖底的那場撞車」。

但 DCTCP 真正的聰明在於它「如何反應」,而這跟那個經典煞車截然不同。普通 TCP 一收到任何壅塞訊號,大致就把視窗砍半——一記又重又統一的踩踏。DCTCP 則改去「量」壅塞有多少:它數一數最近的封包裡,有多少比例是帶著標記回來的。如果幾乎沒有被標記,佇列只是剛要成形,DCTCP 就只把視窗削掉薄薄一片。如果幾乎全被標記,佇列是真的滿了,它就用力收回。這份反應是「按比例的」:輕微壅塞輕點煞車,真正塞車才用力踩。正是這份溫柔,讓佇列保持又短又穩,而不是在「空」與「滿溢」之間瘋狂擺盪。

DCTCP 如何讓佇列保持空著

  1. 交換器盯著自己的佇列。一旦佇列爬過一個小門檻(而不是等它滿),交換器就在經過的封包上設下 ECN 標記,而不是丟掉它們。
  2. 接收者看見標記抵達,並把這份資訊在它的確認回覆裡反射回發送者。
  3. 發送者持續估算「被標記的比例」——它最近的封包裡,有多少份遇上了正在堆積的佇列。
  4. 它依那個比例按比例縮小自己的壅塞視窗:標記稀少就削一小片,標記普遍就大砍一刀。
  5. 因為大家都提早且溫和地反應,那條共用佇列便穩定在又短又恆定的長度——替下一陣 incast 爆量留下了餘裕,而不是滿溢著迎上去。

為什麼這直接幫到 incast:如果瓶頸佇列被保持得又短又幾乎是空的,那麼當四十個回覆一起抵達時,就有真實的緩衝空間去吸收那記尖峰,被丟掉的封包也就少得多。丟得少意味著「卡在逾時上」的流量少,而那本來正是壓垮吞吐量的元凶。DCTCP 並沒有廢除 incast——夠大的扇入仍能淹過任何有限的緩衝區——但藉著在平靜時刻把緩衝區保持空著,它給了爆量一個落腳處。注意這份哲學的轉變:經典 TCP 把緩衝區當成它的壅塞訊號,要等緩衝區滿了才知道自己做過頭;DCTCP 則把「滿的緩衝區」視為一個要避免的失敗,並在那之前老早就發出訊號。

把它兜起來

退一步看,主線就清楚了。資料中心的那些恩賜——龐大的頻寬、微秒級的來回、大量東西向的扇入——正是讓普通壅塞控制絆倒的東西。Incast 把自然的散開—收攏型態變成一場同步的洪水;極小的緩衝區把那場洪水變成丟掉的封包;微秒級來回與毫秒級逾時之間的錯配,又把那幾個丟掉的封包變成一個停滯的請求。配上 ECN 標記的主動佇列管理,加上一個像 DCTCP 這樣會讀那些標記、按比例反應的傳輸協定,從根源切斷了這條鏈條——靠著把佇列保持得很短,好讓爆量有處可去。

繼續往上爬時,把兩條誠實的界線放在眼裡。第一,這一切都跟安全或正確性無關——DCTCP 改變的是「發送者何時放慢」,而不是「資料是否可靠或加密」;TCP 仍然可靠但不保密,加密的活仍由 TLS 來做。第二,壅塞控制只是延遲故事的一半。就算佇列完美地空著,你仍得付出那趟最起碼的來回、以及兩端 TCP 與作業系統機器的那份工——而對某些資料中心工作來說,連幾十微秒都嫌太多。那正是最後一篇接手的地方:繞過核心、徹底重塑傳輸的 RDMA,在這場奔向微秒的競賽裡。