傳輸層

行頭阻塞(head-of-line blocking)

想像一條單排的結帳隊伍,最前面的人正在翻找剛好的零錢。後面所有人都卡住了——不是因為他們沒準備好,而是因為規則說隊伍必須嚴格按次序服務。行頭阻塞就是這種挫折的網路版:前頭一個卡住的項目,把排在它後面的一切都擋住,連那些完全準備好的也一樣。

在 TCP 中,它直接源自依序的位元組串流。TCP 必須嚴格按次序把位元組交給應用程式,所以若有一個區段遺失,每個在它之後到達的區段都得在接收端的緩衝區裡等著——無法被交付——直到那個遺失的被重送、缺口被填滿。缺口後面的資料明明就在那兒、正確又完整,但依序的承諾不准把它交上去。當一條 TCP 連線同時載著好幾樣獨立的東西時,這格外痛苦:單一個遺失的封包會卡住全部,連沒丟任何東西的也卡。

為什麼重要:行頭阻塞是 TCP「可靠加上依序」保證的內建代價,凡是把獨立的串流硬塞進同一條依序通道的地方都會出現。HTTP/2 在一條 TCP 連線上多工許多請求,正好一頭撞上它:一個遺失的封包就卡住那條連線上的每個請求。這個問題催生了 QUIC,它跑在 UDP 之上,給每條串流各自的排序,所以一條串流的丟失不會擋住其他串流——而 HTTP/3 就是跑在 QUIC 上的 HTTP。注意這是該問題在傳輸串流層面的版本;同一個名稱也用來描述較低層交換器緩衝的一個類似問題。

HTTP/2 在一條 TCP 連線上同時送出一個頁面的 HTML、CSS 與三張圖片。一個載著部分 CSS 的封包遺失了。即使所有圖片資料都已完整到達,TCP 仍把它扣住,直到那個 CSS 封包被重送——每樣資源都卡在一個丟失後面。

一個遺失的封包,在依序串流中卡住它後面的一切。

行頭阻塞是依序傳遞的代價,不是 TCP 的臭蟲。QUIC 透過在 UDP 之上給每條串流獨立的排序來繞開它——這正是 HTTP/3(跑在 QUIC 上的 HTTP)避開了 HTTP/2 那種跨串流停頓的原因。

又稱
HOL blockingHoL blocking行頭阻塞隊頭阻塞