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

延遲、吞吐量、有效吞吐量,與瓶頸

有三個詞,大家常當成同一回事在用,其實它們指的是三件非常不同的事,而把它們搞混,正是談網路效能時最常見的單一錯誤。這篇會把延遲、吞吐量與有效吞吐量拆開來看,指出瓶頸究竟落在哪裡,並說明一條再多錢都買不過去的規則:你沒辦法花錢繞過光速。

三個詞,三種意思

到這裡,你已經跑過 iperf,看著它回報一個以每秒百萬位元為單位的數字;你也跑過 ping,看著它回報以毫秒為單位的數字。這兩個數字量的是完全不同的東西,而整個網路領域裡最常見的混淆,就是把它們當成同一件事。所以我們把話說清楚。延遲是一個位元從這裡走到那裡所花的時間:一段時長,以毫秒計。吞吐量是資料一旦開始流動後,實際上每秒能流過多少位元:一個速率,以每秒百萬或十億位元計。一個是延遲,另一個是流量。它們可以彼此完全獨立地變化。

有個比喻能把這釐清。想像一條高速公路。延遲是一輛車從一座城開到下一座城所花的時間,主要由距離與速限決定。吞吐量是每分鐘有多少輛車駛過某一點,由開了幾條車道決定。把路從兩線拓寬成十線,每分鐘能通過的車多得多——那是更多的吞吐量——但它不會讓任何一輛車早一秒抵達,因為路程的長度從未改變。頻寬和延遲是兩個不同的旋鈕,轉動其中一個並不會轉動另一個。

延遲其實是由什麼組成的

Ping 給你一個數字,但那個數字是四種非常不同的延遲加總起來的,而知道哪一種佔了大頭,是診斷的一半工夫。第一,傳輸延遲:把一個封包的位元推上線路所花的時間,等於封包大小除以鏈路速率。第二,傳播延遲:那些位元以光速橫越那段距離所花的時間,它只取決於長度,且完全不受鏈路有多快的影響。第三,處理延遲:每台路由器讀取標頭、決定往哪轉送所花的短暫片刻。第四,也是那個製造麻煩的,排隊延遲

要小心別把傳輸延遲和傳播延遲搞混,因為它們看起來相似,行為卻相反。傳輸延遲會在你買了更快的鏈路時縮小——更粗的管子能更快把一個封包排空到線路上。傳播延遲無論你付多少錢都不會動,因為它只由距離與物理決定。這正是為什麼更多頻寬能幫到傳輸,卻永遠碰不到長距離旅程底下那層光速地板。

排隊延遲是那個會劇烈擺盪的,也是大多數「慢」抱怨的核心。當封包抵達路由器的速度比外送鏈路排空它們的速度還快,它們就會在一個緩衝區裡等待——結帳隊伍。一個幾乎空著的佇列什麼也不加;一個逼近容量的佇列卻能加上數十甚至數百毫秒,而鏈路越接近滿載,等待增長得越凶猛。回想壅塞控制那一級:這正是為什麼一條使用率 99% 的鏈路,感覺上可能比 80% 的那條糟糕得多,即使它只多搬了一點點資料。流量幾乎沒變;等待卻爆炸了。

吞吐量對有效吞吐量:真正算數的位元

現在來看第三個詞,多數人從沒聽過的那個。吞吐量數的是每一個橫越鏈路的位元,但並非每個位元對你都有用。每個封包都帶著各種標頭——乙太網路訊框、IP 標頭、TCP 標頭——全是你早先學過的分層所帶來的定址與記帳開銷。再加上用來重傳遺失封包的位元,以及純粹的協定閒談(例如確認)的位元。有效吞吐量就是吞吐量減去這一切之後剩下的:實際上完整、依序抵達的應用資料的速率——檔案或影片的那些位元組,別無其他。

Carrying a 1000-byte chunk of your file over Ethernet:

  application data ............ 1000 bytes  <- what you want
  + TCP header ................   20 bytes
  + IP header .................   20 bytes
  + Ethernet frame overhead ...   38 bytes
  ----------------------------------------
  total on the wire .......... 1078 bytes

  goodput / throughput  =  1000 / 1078  ~=  93%

And that is the GOOD case: zero loss, zero retransmission.
Lose and resend a packet, and goodput drops further still.
吞吐量數的是線路上的一切;有效吞吐量只數抵達的應用位元組。標頭與重傳,就是兩者之間的差距。

所以有效吞吐量永遠小於或等於吞吐量,而那道差距會說故事。差距小,代表傳輸有效率、損失很少。差距大——吞吐量逼近鏈路速率,有效吞吐量卻遠在其下——是一面紅旗:你推送了大量位元,卻在遺失與重送其中許多,於是線路很忙,使用者卻在等。這正是為什麼一個吹噓吞吐量的測速可能仍感覺遲鈍,也是為什麼有效吞吐量——真正算數的那些位元——才是一次傳輸的誠實量尺。

瓶頸落在哪裡

一條端到端的路徑是一串鏈路,每段都有自己的速率。整條路徑的吞吐量不可能超過鏈中最慢的那段鏈路,而那最慢的一段就是瓶頸。如果你家裡的鏈路跑 100 Mbps、骨幹光纖跑 10 Gbps,這條路徑的天花板就是 min(R1, R2) = 100 Mbps。升級瓶頸以外的任何一段鏈路都改變不了什麼;把一條六線道拓寬卻通往一座單線橋,並不能讓更多車通過。整個效能的遊戲,就是找出那一段真正在限制你的鏈路。

在這裡,延遲與吞吐量匯聚成一個美麗的想法:頻寬延遲乘積,也就是頻寬乘以來回時間。它是當鏈路完全忙碌時、正在飛行中(填滿管子)的資料量——也就是管子本身的容積。把它想成一條水管:它的容量等於橫截面積(頻寬)乘以長度(延遲)。要讓一條又粗又長的管子保持滿載,發送端必須同時有那麼多位元組在途中尚未確認,這正是為什麼 TCP 的窗口至少要大到等於頻寬延遲乘積,否則鏈路就會半閒著、空等著確認。

套上實際數字。一條橫越海洋、來回時間 100 毫秒的 1 Gbps 鏈路,其頻寬延遲乘積是 1 Gbps 乘以 0.100 秒,等於 100,000,000 位元,約 12.5 百萬位元組——這就是要讓它保持滿載必須在飛行中的資料量。如果 TCP 一次只允許 64 KB 尚未確認,發送端就送出 64 KB 後停下,整整等上 100 毫秒才等到確認,於是那條 1 Gbps 管子只跛行在不到其速率 1% 的水準——不是因為鏈路慢,而是因為延遲。在這樣一條又長又粗的管子上,限制是來回一趟、而非頻寬,這正是為什麼高延遲的路徑即使在快速鏈路上也感覺很慢。

緩衝區、緩衝膨脹,與讀懂症狀

還有一個陷阱,把延遲與吞吐量之間的迴圈收尾。為了避免在突發流量中丟掉封包,工程師給路由器和家用閘道器配了大型緩衝區。這看似仁慈:與其丟掉一個封包,不如先留著它。但瓶頸處一個過大的緩衝區會悄悄填滿、並維持滿載,於是現在每個封包都得排在一條長長的常駐佇列後面等待。結果就是緩衝膨脹:吞吐量看起來沒問題,負載下的延遲卻膨脹到數秒之久。你的下載很快,而你的視訊通話同一刻、在同一條鏈路上,卻爛到沒法看。

把這套詞彙當成一份診斷清單來用。延遲高但吞吐量正常,指向距離或一個膨脹的佇列,而非慢鏈路。吞吐量低但延遲正常,指向瓶頸鏈路的速率,或一個對頻寬延遲乘積來說太小的窗口。吞吐量遠高於有效吞吐量,指向遺失與重傳。而閒置時延遲正常、負載下卻糟透了,正正指向緩衝膨脹。把症狀講得精確,正是它告訴你該去修哪一段鏈路、哪一個機制——這就是本級最後一篇要談的主題。