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

服務品質:排程與監管

一台佇列塞滿的路由器,得做一個選擇:誰先走、誰得等?本篇打開那個盒子,讓你看見裡頭兩台簡單的機器——一個排程器,決定誰的封包先離開;一個監管器,決定誰的封包根本能不能進來。

「服務品質」到底是什麼意思

這一級的前三篇,一直繞著一個讓人不安的事實打轉:網際網路什麼都不保證。你的 VoIP 通話,和某個陌生人的大檔下載,灌進同一個路由器佇列,被一模一樣地對待,一起碰運氣。這就是盡力而為服務——網路盡它最大的努力,但對延遲、丟失、抖動,一概不擔保。服務品質(QoS)則是一把大傘,罩住所有「讓網路把某些流量待得比其他流量更好」的機制,好讓真正需要低延遲的封包,真的能拿到低延遲。

關鍵的思維轉變在這裡。盡力而為把所有封包當成排在同一條隊伍裡、地位平等的陌生人。QoS 則說:封包並非生而平等,而且網路是被允許厚此薄彼的。一個遲到 200 毫秒的語音封包是廢物——它本該被聽見的那一刻已經過去了。一個遲到 200 毫秒的檔案下載封包卻完全沒問題;沒有人等著那一毫秒。所以,若一台路由器非得選「下一個送誰的封包」,先送語音封包,幾乎不花下載什麼成本,卻救了那通電話。QoS,就是那套讓路由器能「刻意」做這個選擇、而不是「碰巧」做出選擇的機器。

排程器:誰是下一個離開佇列的

每個路由器的輸出埠都有一個緩衝區——一間候診室,當封包抵達的速度比鏈路送得出去的速度還快時,它們就坐在這裡。路由器用來「挑下一個封包離開候診室」的規則,就是它的排程紀律(scheduling discipline),而「靠排程做 QoS」這整件事,全在於選哪一條規則。預設的那條最無趣:FIFO(先進先出),就像銀行裡只開一個櫃台的單一隊伍。先到的先走。在最樸素的意義上它完全公平,但它根本不知道「一個語音封包比它前面那個大檔下載更急」——於是急的封包,得排在不急的後面乾等。那段等待,就是你在基礎那一級認識的佇列延遲,而 FIFO 完全不會去體諒那些最等不起的流量。

最簡單的補救是優先權排程(priority scheduling):把封包分成幾個類別——比方說,一個給語音的高優先權類別,一個給其餘一切的低優先權類別——然後永遠先服務高優先權佇列,只在它空了的時候,才去碰低優先權那個。現在語音封包每次都插隊,你的通話保持清晰。但請注意,隨這份權力免費附贈的危險:如果高優先權類別永遠不見底,低優先權流量就可能永遠等下去。這叫做飢餓(starvation),是嚴格優先權的陰暗面。把絕對優先權給語音,一陣語音的洪水就能把下載掐到動彈不得。純優先權是把鋒利的工具:對一個小而守規矩的緊急類別來說無比好用,但若那個類別沒被管小,就很危險。

加權公平佇列(WFQ)是個成熟的答案,兼收兩者之長。給每個類別自己的佇列、自己的權重——一份對鏈路有保證的份額。一個權重為 3 的類別,每當它和權重為 1 的類別都有封包在等時,大約能拿到後者三倍的吞吐量。排程器在各佇列之間輪轉,給每個它被承諾的那一份,於是語音類別可以被保證、比方說、鏈路的 30%,永遠不會挨餓;下載類別也被保證它那一份,同樣餓不死。優雅之處在於:當某個類別沒東西可送,它那一份就借給別人,於是鏈路永遠不會被浪費。WFQ 是一種「帶旋鈕的公平」——你選定權重,而沒有人會被鎖在門外。

Three packets waiting at one output link. V = voice (urgent), D = download.

FIFO          : D D V D D   -> sends D, D, V, ...   (V waits behind two D's)
PRIORITY      : V always first -> V, then D's        (but D can starve)
WFQ (V:D = 3:1): rotates by weight -> V V V D V V V D  (both guaranteed a share)

Same packets, three different rules for "who goes next" -- that choice IS QoS.
同一批等待的封包,在三種排程紀律下的命運。FIFO 無視急迫性;嚴格優先權可能餓死下載;加權公平佇列則保證每個類別一份可調的份額,同時把任何閒置的容量借出去。

監管器:誰被允許進來

排程決定的是「已經在佇列裡的封包」的順序。但還有第二個、更早的問題:這個封包,到底該不該被放進來?排程器的承諾,唯有當每個類別都守在它被承諾的速率之內時才成立——如果語音類別被允許用三倍於約定的速率猛送,它的保證就形同虛設,還會傷到其他每個人。於是網路加上一個守門人,量測每條流的速率並強制一個上限。在邊界檢查並執行這個上限,叫做流量監管;在一條流進入網路之前,把它從爆量重塑成平順,叫做流量整形。目標相同——把一條流關在它約定的範圍內——但監管器當場懲罰違規,整形器則溫和地把封包延後,直到它們守規矩為止。

課本上描繪「嚴格速率限制」的方式,是漏桶。想像一個桶,底部有個小洞。抵達的封包,是從頂端倒進去的水;那個洞讓水以一個固定、穩定的速率流出,不管你倒得多兇。如果你倒得比洞排得掉的還快,桶就滿了,一旦溢出,多餘的水就直接灑掉——那些封包被丟棄。於是不管輸入有多爆量,輸出永遠是平順的、就是那個排水速率。這是把一條尖刺的流變平的、絕美又簡單的辦法。它的弱點恰恰是它的僵硬:它完全不容許任何爆量,連網路明明還有空間容下一陣爆量的時候也不行——這對本來就一陣一陣的流量,可能嚴苛得沒有必要。

更聰明的那位表親,實務上幾乎無所不在,是令牌桶——而它把畫面整個倒了過來。現在桶裡裝的是令牌,不是封包。令牌以穩定速率 r 滴進來、堆積起來,但桶最多只能裝 b 個。要送一個封包,你得花掉一個令牌;沒令牌,就不准送。兩個參數道盡一切:r 是你被允許的長期平均速率,b 是你被原諒的爆量有多大。如果一條流安靜了一陣子,令牌就累積到 b,接著它便可以一口氣送出最多 b 個封包的突發——網路用「讓你兌現存下來的額度」來獎勵好行為。「平均速率,加上一份爆量額度」這單一的點子,比漏桶那種平板的細流,遠遠更貼近真實流量實際的模樣。

把兩台機器合起來

排程與監管,是同一個設計的兩半,而它們只有成對才管用。監管器是門口的保鑣:它用令牌桶量測每條流,執行那筆交易——守在你的速率 r 之下、爆量不超過 b,否則你超出的封包就被丟棄或被標記。排程器則是門內的主人,決定所有過了門的人的順序,用優先權或 WFQ,把被承諾的份額分給每個獲准進來的類別。監管器讓排程器的承諾守得住;排程器把獲准的流量,變成每個類別需要的那種體驗。少了任一個,都只是半套系統。

  1. 一個封包抵達路由器,藉著讀取它標頭裡的一個標記,被歸類進某個流量類別——例如,語音對上大宗資料。
  2. 監管器檢查那個類別的令牌桶:若有令牌可用,封包就被放行;若無,封包就被丟棄,或被標記為「超出約定」。
  3. 被放行的封包,加入它所屬類別自己的佇列,等待輪到它離開輸出鏈路。
  4. 排程器挑出下一個要送的封包——對緊急類別用嚴格優先權,或用 WFQ 給每個類別它加權後的份額——然後被選中的封包離開。

為什麼這比看起來難得多

到此為止講的,都是一台路由器。誠實的難處在於:一個封包穿越網際網路時,會經過許多由許多不同公司營運的路由器,而一個保證的強度,只等於它最弱的那一跳。如果路徑上每台路由器都細心地排程與監管你的語音流量,卻有中間一台把它當成普通的盡力而為來對待,你的通話在那裡依然會受苦。所以,一個真能兌現保證的 QoS,需要路徑上每一台路由器都合作、都遵守同一份協議——而這件事,在一家公司自己的網路裡要求起來,遠比在「沒有人說了算」的開放網際網路上容易得多。

還有一個與緩衝區本身微妙的交互作用。階梯前段你遇過緩衝膨脹(bufferbloat)——把路由器緩衝區做得太大的陷阱,於是封包堆積、一坐就是好幾百毫秒,恰恰毀掉了 QoS 本該保護的低延遲流量。一個巨大的 FIFO 緩衝區幫不了即時媒體;它反而傷害媒體,因為就算技術上什麼都沒丟,它也加進了延遲。所以好的 QoS,既關乎「讓正確的佇列保持短」,也關乎「選誰先走」。配上合理上限的、按類別分開的聰明佇列,每一次都勝過一個巨大的共用緩衝區。

於是我們手上有了這些積木:類別、排程器、監管器、桶。剩下的問題是,怎麼把它們接成一套「整網」的架構——你要事先為每一條個別的流預留資源,還是只在每個封包上蓋一個類別的章、讓路由器處理類別而非個別的流?這正是那兩個偉大的答案,整合式服務(IntServ)差異化服務(DiffServ),以及一個出人意料的原因——為什麼真實的網際網路大多兩者都跳過、就守著樸素的盡力而為。那,就是這一級最後一篇的故事。