揭祕HTTP/3優先順序

語言: CN / TW / HK

圖片

編者按 / 相對於HTTP2,HTTP/3的優先順序更加簡單,瀏覽器廠商更可能實現統一的優先順序策略。本文來自老朋友Robin Marx,已獲授權轉載,感謝劉連響對本文的技術審校。

翻譯 /  核子可樂

技術審校 / 劉連響

原文連結 / http://calendar.perfplanet.com/2022/http-3-prioritization-demystified/

如果大家做過Web效能調優,可能會聽說過HTTP資源優先順序。這波趨勢從去年開始風頭愈勁,因為Chromium通過新的fetchpriority屬性引入了所謂“優先順序提示”,允許開發者進行優先順序調整。另外,HTTP/2和HTTP/3之間的優先順序系統也發生了變化。

但是,這個優先順序究竟是什麼?它是怎麼起效的?為什麼有必要加以控制?而且最關鍵的,是不是所有瀏覽器都對資源的重要性擁有共識(當然不是)?順著這個思路,我們就一起說道說道:

  • 優先順序究竟是什麼?

  • 資源載入延遲

  • 優先順序訊號

  • 瀏覽器差異

  • 原始協議細節

  • 主要結論(可能是您最感興趣的部分)

  • 伺服器差異

  • 總結

注意:HTTP優先順序是個非常寬泛的話題,甚至專門寫篇博士論文都沒問題。所以在本文中,我刻意忽略掉了很多細微差別,只專注討論幾個關鍵點。

01 優先順序究竟是什麼?

HTTP資源優先順序,屬於主要面向HTTP/2(H2)和HTTP/3(H3)的概念。在HTTP/1.1(H1)中,瀏覽器往往會開啟多個TCP連線(每個域最多6個),且每個連線每次僅載入1個資源/檔案。這裡的優先順序隱式存在,代表在可用連線上首先請求資源。

但在H2和H3這邊,我們目標是僅使用單一TCP/QUIC連線來提高效率。但如果單一連線也只能像H1那樣每次只有一個資源處於“活動”,那肯定不利於效能表現。所以H2和H3可以同時傳送多個請求。但請千萬注意,這並不是說這多個請求就一定能同時得到充分響應。因為在任意給定時間,連線所能傳送的資料量都受到擁塞和流量控制等因素的限制。

圖片

圖一:典型的擁塞控制演算法對慢啟動管理得很嚴,對後續延遲增長則表現得較為寬容。

特別是在連線啟動時,我們只能在每次網路往返中傳送有限數量的資料,因為伺服器需要等待瀏覽器確認其已成功接收到每波突發資料。也就是說,伺服器需要選擇到底先響應多個請求中的哪一個。

舉例來說,瀏覽器已經載入了.html頁面,並在一個H2/H3連線上同時請求了3種資源:一個被延期的JS檔案(100 KB)和兩個.jpg影象(分別為300和400 KB)。假設伺服器在此次往返中只能傳送50 KB資料(約35個數據包,具體數字取決於各種因素),那現在就得決定怎麼填充這35個數據包了。所以,到底該首先發送什麼?

我們可以說JS總是最重要的(高優先順序),哪怕存在延期也是。或者,我們也可以說其中一張影象可能是Largest Contentful Paint(審校者注:LCP,即最大內容繪製,用於監控網頁可視區內“繪製面積”最大的元素開始呈現在螢幕上的時間點。)的候選物件,所以應該優先發送其中一張(但到底是哪張?)。我們甚至可以說jpg影象可以逐步顯現,所以分別給每張影象25 KB的配額(這就是所謂資源資料的「交錯」或多路複用)。但如果延期的JS就是實際載入LCP影象的主體……那是不是也得給它分配點頻寬?

圖片

圖二:可以用多種方式為三種資源分配頻寬。

很明顯,這裡伺服器做出的選擇會對各項Webperf指標產生重大影響,畢竟某些資源資料將始終被置於“更高優先順序”的“重要”資料之後。如果先發送JS,那麼影象會延遲1次或經歷多次網路往返,反之亦然。這一點對(渲染阻塞)JS和CCS的影響尤其明顯,因為其需要完整下載後方可應用/執行。

圖片

圖三:如果資源以交錯/多路複用方式載入(上方),則會拖慢其完全載入的速度。

注意:這就是我反對人們總說什麼H2和H3允許並行傳送多個資源的理由,因為這根本就不叫真正的並行!H1反而比H2/H3並行得多,因為前者有6個獨立連線。充其量,H2/3資料只能算線上路上交錯或多路複用(例如將配額分別給予兩張影象),但常規響應仍是按順序傳送(先是完整載入第一張影象,之後是第二張)。所以作為一個“學究”,我還是更傾向於併發資源(或者叫並行請求和多路響應)。

這裡的問題在於,伺服器並沒有足夠的資訊來做出最佳選擇。事實上,它甚至不知道JS檔案在HTML被標記為延期(defer),因為瀏覽器的HTTP請求中並不包含這段上下文(而且伺服器往往不會親自解析HTML來發現這些修飾符)。同樣的,伺服器也不知道影象是否立即可見(例如,在viewport中)或者尚未可見(使用者需要向下滾動才能看到輪播中的第二張圖)。至於新鮮上架的fetchpriority屬性,伺服器更是聞所未聞。

所以擁有足夠上下文來決定該先載入哪種資源的,其實是瀏覽器。它需要一種方式將首選項傳遞給伺服器,而這就是HTTP優先順序機制的由來:一種瀏覽器向伺服器傳送資源請求具體順序的標準化方式。

資源載入延遲

這裡要提醒大家,優先順序並不是影響實際資源交付順序的唯一因素。畢竟優先順序決定的僅僅是如何處理同時處於活動狀態的多個請求。有些朋友可能以為,對於HTTP/2和HTTP/3,瀏覽器可以在HTML中發現資源後立即提出請求,再單靠優先順序排序來獲得正確的響應。不好意思,做不到的。

實際上,所有瀏覽器都或多或少具備一些(高階或基礎)邏輯,用於主動延遲某些請求,即使在發現資源之後也是如此。舉個簡單的例子,預取資源通常會在中的元素中指示,但僅在當前頁面載入完成時由瀏覽器請求。

另一個例子就是Chromium的“緊湊模式”,它會主動延遲掉不太重要的資源(例如HTML中的影象、CSS和JS),直到(大部分)更重要的資源載入完成。再有,同時啟用的預載入資源也有限制。

我們可以通過以下瀑布圖看到,部分資源即使被發現得更早,也只會在一段時間後才被請求。

圖片

圖四:在Safari中,這些資源在被發現後也不會被同時請求。

在實踐當中,瀏覽器同時傳送哪些請求、各請求之間的優先順序關係間存在著相當複雜的相互作用。受篇幅所限,本文就不過多討論了。當然,我接下來要介紹的測試方法確實可以實現這種影響分析,這也是我個人的下一步研究方向。

02 優先順序訊號

檢視瀏覽器開發工具中“Network”選項卡下的優先順序列(參見上圖四),就會看到由高到低(或者類似排序)的文字數值。您可能覺得這就是傳送至伺服器的內容,但很遺憾,情況並非如此。

特別是在HTTP/2中,有一套更高階的系統在起作用,就是所謂“優先順序樹”。在這裡,資源以樹狀資料結構排列。資源在樹中的位置(父項和兄弟項分別是什麼)與所關聯的“權重”會影響其何時獲得頻寬、獲得多少頻寬。在請求資源時,瀏覽器會使用特殊的附加HTTP/2訊息(PRIORITY幀)向伺服器表達該資源在樹中的位置。

圖片

圖五:Firefox使用複雜的HTTP/2優先順序樹。

這套系統如此靈活和強大,但事實也證明其非常複雜,甚至是過度複雜。以至於即使在今天,不少HTTP/2在具體實現上都有嚴重的錯誤,另一些堆疊則根本無法實現(直接忽略瀏覽器的訊號)。不同瀏覽器使用該系統的方式也存在巨大差異。

因此在HTTP/3當中,我們才決定建立一套更簡單的系統,這最終成了RFC 9218:HTTP的可擴充套件優先順序方案。這種方法沒有完整的樹狀結構,只有8個數字的優先順序(即「緊急度」,取值在0到7之間)外加一個“增量”布林標記,用於指示資源能否與其他資源交錯(漸進式jpg:可以交錯;渲染阻塞JS:最好不要交錯)。預設情況下,資源的緊急度為3且非增量。

圖片

圖六:新系統使用兩個引數——緊急度與增量

其中的概念非常簡單:伺服器應首先發送具有最高非空優先順序組內的所有資源(u0應在u1前處理等),之後再繼續下一個組。因此只有還有一種u=0的資源處於活動狀態(而且我們有資料要傳送給它),就不應為其他緊急組傳送資料。在同組之內,資源則按請求順序傳送(由先到後),因此中靠前的JS會在中靠後的JS前交付。

注意:如果一個緊急組內只有增量或非增量資源,那麼情況當然很簡單(審校者注:“incremental”沒有非常恰當的中文說法,暫且譯成“增量”。)。而一旦增量與非增量資源混合起來(比如前文示例,一個非增量JS和兩張增量影象均在u=3組內),處理難度就上來了。我們要不要先把完整的JS傳送完(因為它是非增量的)?還是說,我們該為影象提供部分先期頻寬(因為它們的優先順序相同,而且可以增量傳送)?很遺憾,RFC本身並沒有給出具體指導,因為每種選項都有利弊。

新系統在傳送緊急和增量訊號的方式上也更簡單:這裡使用的並非特殊的HTTP/3訊息,而是名為priority的新文字HTTP標頭。這種總體更簡單的方法降低了實現和除錯難度,而且有望帶來比H2系統更好的支援並減少bug(劇透一下,其實也還做不到)。

圖片

圖七:新系統使用新的“Priority”HTTP標頭。

但有時候好想法就只是個想法。實際HTTP標頭只能用於表達資源的初始優先順序,一旦稍後需要更新優先順序(比如延遲載入的影象最初獲得低優先順序,但在滾動至檢視內時需要切換至高優先順序),那單靠HTTP標頭就實現不了了。為此,我們還是需要特殊的H3(和H2!)二進位制訊息:PRIORITY_UPDATE幀。這些細節對大多數人來說並不重要,但我還是想做做強調,畢竟HTTP標頭有Firefox和Safari在用,但Chromium卻根本沒用。出於“種種原因”,谷歌只使用PRIORITY_UPDATE框幀來表示初始優先順序(會立即覆蓋掉預設優先順序)。

需要注意的是,這種新方案也並非HTTP/3所獨有。其目標就是隨時間推移,將功能移植到現有H2實現當中(但據我所知,目前還沒有H2堆疊實際採用)。另外,它之所以被稱為“可擴充套件”的優先順序系統,是希望能在未來引入“緊急度”和“增量”以外的更多其他引數。

03 瀏覽器差異

正如前文提到,不同瀏覽器使用複雜HTTP/2系統的具體方式也有很大區別。各種主流瀏覽器引擎(Chromium、Firefox、Safari等)會生成截然不同的優先順序樹和訊號。

但在接下來的部分,我將只關注HTTP/3上的新系統,畢竟所有三種主流瀏覽器都能支援。我想搞清它們在新系統的實現方法上是否還有差異。但經過檢索,我發現只有Chrome釋出了關於具體方法和邏輯的開放文件,而Safari和Firefox那邊壓根沒有任何研究資料。所以,我只好親自動手了!

開始之後,我馬上遇到了兩個問題:

  1. 新訊號的觀察非常困難,因為目前還沒有相應的支援工具。這些訊號不會以原始形式出現在瀏覽器的開發工具中,也不會出現在WebPageTest內。所以我決定修改aioquic HTTP/3伺服器,為優先順序訊號新增一些額外的日誌記錄。

  2. 我四處檢視,但沒有哪個測試頁面能包含所有可能影響優先順序的全部資源載入項(非同步/延期、懶載入/急載入、fetchpriority、預載入/預取等)。所以我建立了自己的測試頁面,其中包含多達36種不同的情況。

之後,我在自定義HTTP/3伺服器上託管了自定義測試頁面,並分別用三款瀏覽器進行載入。我儲存了來自瀏覽器的HAR(審校者注:HAR即HTTP Archive format, 一種HTTP請求存檔格式。)檔案和來自伺服器的日誌,想搞清楚瀏覽器通過網路到底傳送了什麼內容。感興趣的朋友可以在GitHub上(http://github.com/http3-prioritization/prioritization-experiments)檢視完整資訊,接下來我只談其中比較重要的部分。

原始協議細節

下面,我會從原始底層結果開始討論。如果大家不關心細節,可以直接跳往下一節閱讀巨集觀層面的解析。

圖片

圖八:部分原始結果。

首先,如前所述,Chromium只使用PRIORITY_UPDATE框架,而未使用HTTP標頭。Firefox和Safari則相反,僅使用標頭。受測試頁面的性質決定(僅包含初始載入),所以我無法觀察瀏覽器是否真的傳送了更新。但在原理上,Chromium肯定會為影象執行此操作(先將其視為低優先順序,之後在影象需要可見時再更新為高優先順序)。在這種情況下,Chromium只會傳送2個PRIORITY_UPDATE幀,其一用於初始優先順序,其二用於後續實際更新。再聊點純技術細節:初始PRIORITY_UPDATE的傳送次序在HTTP標頭之前。

第二個重要區別,就是增量引數的使用。Chromium和Firefox會預設將其設定為“關閉”,就是說伺服器不會在多個資源間分配頻寬;最重要的資源必須先被完全載入,之後再轉往下一個。Safari則相反:它會為所有資源型別設定增量引數,包括渲染阻塞的JS和CCS資源。但前面也提過,這兩種作法其實各有問題。

另外需要強調一點,Chromium的執行邏輯已經有了明確的調整計劃。據我所知,後續更新會為Chromium內的所有內容設定增量引數,除了(高優先順序的)JS和CSS檔案。這有助於解決一些長期存在的錯誤,比如大規模HTML下載可能無端導致渲染阻塞CSS發生延遲。開發團隊顯然意識到Chromium採取的純按序載入機制的缺陷。更重要的是,這意味著與HTTP/3相比,Chromium會對HTTP/2使用不同的優先順序邏輯(HTTP/2也未使用類增量引數機制)。視具體設定而定,這項調整計劃可能會對頁面產生很大影響,所以建議大家儘快切換至HTTP/3。最後需要注意的是,Firefox也有類似的情況,已經在HTTP/2中使用增量訊號,但在HTTP/3中卻沒有。

第三,不同覽器間的訊號使用方式也有細微差別。例如,Chromium和Firefox不會明確傳送“u=3”的訊號,因為這是伺服器所遵循的預設值。但Safari卻會明確傳送“u=3,i”。此外,瀏覽器使用的緊急度值也有不同。在內部,Chromium和Safari使用的是5檔優先順序(分為:最高、高、中、低、最低),而Firefox似乎只使用4檔。Chromium的緊急度數值為(0,1,2,3,4),Safari分得更開(0,1,3,5,7),Firefox則直接跳過了0(1,2,3,4)。這應該不會影響伺服器的資源交付方式(緊急度值的比較關係更重要,具體使用哪個數字其實無所謂),但有趣的是,即使是這樣一套簡單系統,市面上也出現了三種不同的實現方法。

對於以下主要結論,我選擇最高、高、中、低、最低的5檔緊急度劃分方式(Firefox只到4,所以不存在「最低」這檔)。

主要結論

跟大家預想的一樣,除了協議細節之外,瀏覽器為不同資源型別和載入方法分配的重要度也有很大差異。下面我交討論幾組資源型別(HTML與字型、CSS、JS、影象、提取)以及三款瀏覽器間的一些主要區別。請注意,我會盡量避免去評判哪種方法更好,畢竟這取決於特定頁面設定和使用到的功能。希望大家儘量把我給出的結論,當作在不同瀏覽器之上開展效能調優的參考意見。

圖片

幸運的是,三款瀏覽器都認為主HTML檔案是最重要的(雖然實際上也未必)。而在字型方面,三者的權重就不同了。Chromium認為字型跟HTML本體一樣重要,而Safari和Firefox則將其置於中甚至是低優先順序。特別是跟CSS和JS街霸減倉資源的優先順序進行比較後,我們發現Chromium對字型的重視程度確實遠超另外兩款瀏覽器。字型預載入也很有趣:在這方面,Chromium實際上是降低了優先順序(可能是因為預載入對應的是將要需要、而非立即需要的資源)。Firefox則採用相反的邏輯,為預載入字型分配了更高的優先順序。

圖片

對中CCS進行載入的關鍵區別在於,Chromium會將其視為最高優先順序,等同於HTML檔案;而其他兩種瀏覽器則將全部CSS都視為“高”類別。對於HTML中排序靠後的CSS(在我的測試用例中甚至是墊底位置),Chromium有趣地將其列入“中”類別(這是對的,畢竟它並不是真正的「渲染阻塞」)。所有瀏覽器都準確將帶有media="print"的CSS放置在了最低優先順序(除了Firefox,因為它沒有「最低」這項)。

圖片

至於JS,幾乎可以說是隨處優先。所有瀏覽器都要求積極處理中的沉浸阻塞JS。而除此之外,對於預載入JS,只有Firefox調低了其優先順序(可能是採用了Chromium的字型處理邏輯),而且所有瀏覽器都正確地顯著下調了預取JS的優先順序。但非同步/延期部分有點奇怪,Chromium和Firefox都為其分配了相同的優先順序。就個人而言,我覺得延期的定義就該決定它優先順序更低。Safari就更奇怪的,它反倒把延期的優先順序設得比非同步更高(我真的完全理解不了這一點)。另外,Safari給稍後載入的JS分配了與內相同的優先順序,Chromium和Firefox則認為前者應該比內的JS優先順序低。最後,Safari幾乎把所有CSS和JS都劃入了“高”優先順序序列,意味著不那麼重要的檔案也可能拖慢關鍵資源,特別是在Safari對所有請求都使用“增量”引數的背景下。

圖片

對於影象,各瀏覽器的思路比較一致。但其中有個有趣的例外,即Safari調低了懶載入隱藏影象的優先順序(我這個測試頁面中display: none

內的普通),但Firefox和Chromium則認為其優先順序應該與可見影象相同。另外還有兩個明確的例子,能夠說明單純強調優先順序還不夠:預載入和懶載入都根本不會影響到影象優先順序!這些功能只在實際請求資源時才會起效(詳見前文),所以我們才需要新的FetchPriority屬性,這實際上對優先順序機制起到了增強作用(Chromium已經邁出了這一步,有報道稱Firefox也在努力相容)。最後,測試頁面中還包含隱藏的懶載入影象,各瀏覽器均未對其發出請求。

圖片

作為測試的收尾,我打算試試用JavaScript fetch() API發出的請求的優先順序。在這部分,不同瀏覽器的表現又出現了重大分歧。Chromium認為這些請求非常重要,而Firefox則預設將其劃入“低”優先順序(等同於影象,甚至是預取)。我還測試了從延期JS檔案內(第二行)執行fetch() ,並猜測Chromium會給它設定較低的優先順序(跟延期JS本身保持一致),但結果並非如此。這再次凸顯出fetchpriority屬性的重要意義,它能有效幫助Chromium實現優先順序下調。

之後,我又想到覆蓋掉優先順序資訊。畢竟在新系統中,這是靠HTTP標頭完成的,我們可以在fetch()呼叫中設定自定義標頭!不出所料,在手動發出priority: u=0,1 這條標頭後,三款瀏覽器又做出了彼此不同的反應。

圖片

圖九:不同瀏覽器在處理自定義優先順序HTTP標頭時的差異。

Chromium會同時傳送Priority_update幀加自定義標頭。Firefox只發送兩條priority標頭欄位:本身,再加上來自fetch()的欄位。我不敢100%確定,但我猜HTTP RFC應該不允許這種作法吧。畢竟兩個值是矛盾的,所以不清楚伺服器應該選擇使用哪個值(在上表中,我選擇了Firefox的u=4預設值)。最後,Safari用我們傳遞給fetch()的一個標頭覆蓋了自己的標頭,這可以算是“正確”(至少符合預期)的反應。

總體而言,我對瀏覽器允許手動設定標頭感覺有點意外。之前這個問題就在IETF上激起過討論,而且Chromium還明確表示反對。但理論上講,我們能利用這項功能通過自定義優先順序實現細粒度的資源載入——比如單頁應用程式,應該會很有趣!

很明顯,不同瀏覽器在某些資源型別的重要度方面存在重大意見分歧。但這本來可以統一起來的,畢竟其實現根本就不依賴於瀏覽器,而是(HTML)載入語義。從表象上看,各家瀏覽器廠商好像就是一拍腦袋就定下了這些規則,根本就沒有實證資料作為支援(也沒有正確記錄)。好了,吐槽就到這裡,馬上進入下一環節。

04 伺服器差異

如大家所見,即使是在新的和比較簡單的系統當中,不同瀏覽器向伺服器傳送優先順序訊號的方式和思路也有很大差別。但對伺服器來說,這些都不重要:只要按瀏覽器發來的要求執行,儘可能照章辦事就行了。但真是如此嗎?

注意:操作並不總是嚴格按照訊號進行的。特別是在較為複雜的設定中(比如使用CDN),某些優先順序更高的資源可能暫時沒有可用資料(例如尚未被快取在邊緣位置),這時候先發送優先順序較低的資源反而更有意義。

同樣,我發現還沒人對已經非常成熟的HTTP/3伺服器進行過優先順序支援性調查(前不久,才剛剛有人對HTTP/2伺服器做過這方面調查)。靠人不如靠己,我還是決定親自上場。

很遺憾,得到的結果不怎麼好。我測試的伺服器幾乎沒有一個能完全遵循哪怕是比較簡單的優先順序訊號,而且大多數在處理更復雜的訊號組合時還出了嚴重問題。

但這裡我不打算把這些伺服器的名號報出來,畢竟這種羞辱性的展示沒啥建設性。相反,我直接聯絡到伺服器開發團隊,探討該如何解決問題。再過半年或者一年,也許我們可以重新回顧這個話題並分享後續進展。

以下列出的是我觀察到的不良行為,各截圖均來自Chromium載入的原始測試頁面:

圖片

圖十:在相同瀏覽器內載入同一頁面時,HTTP/3伺服器的不同表現。

如您所見,伺服器並不總是根據瀏覽器的訊號接收資料,這當然會對某些Webperf指標產生影響。如果大家已經在嘗試使用HTTP/3,但得到的結果達不到預期,也許原因就在這裡。

就個人而言,我很難理解為什麼會存在這些問題。HTTP/2伺服器之所以表現不佳,一大原因就是HTTP/2的優先順序樹難以正確實現。可以說,新的HTTP/3系統應該更容易做對,可我們在所謂的成熟實現中還是碰上了影響很大的bug……算了,懶得抱怨了😉

05 總結

本文的中心,就是展示不同瀏覽器在通過HTTP載入資源的具體方式上存在巨大差異(優先順序排序只是其中一例)。根據具體頁面設定,您可能在不同瀏覽器間發現中等或較大的Webperf差距,大家應該瞭解這些差距的由來以應對可能出現的極端狀況。

另外,本文還希望向大家展示新的“優先順序提示”及fetchpriority屬性的意義。它們不僅能更改瀏覽器的預設行為,還能跨不同瀏覽器實現更統一的反應方式(如果Firefox和Safari願意接納這些新元素)。

最後,從更廣泛的“軟體工程”層面來講,我發現了一個有趣的現象:再簡單的系統,也不一定就能保證跨平臺間的行為一致,也不能保證堆疊自設計之初就不存在bug。儘管問題多多,我還是為自己參與新的HTTP/3系統的設計工作而自豪。我認為這是朝著正確方向邁出的一步,也希望新成果能被向下移植到HTTP/2實現當中。

鳴謝

特別感謝Barry Pollard、Lucas Pardue和Patrick Meenan為本文撰寫提供的幫助。

對“HTTP/3優先順序揭祕”的四條迴應

1.Web Performance Calendar » The Web Performance Engineer’s Swiss Army Knife December 26th, 2022

[…] 隨著HTTP/3的推出,HTTP/2安享的靜好歲月被打破了。Robin Marx之前曾發文討論過優先順序排序中的一些細微差別 […]

2.Web Performance Calendar » LCP attribution: a fetchpriority breakdown December 30th, 2022

[…] 除了通過web vitals attribution瞭解關於fetchpriority的資訊,我還再次體會到HTTP優先順序排序確實是件複雜的事情。[…]

3.HTTP/3 Prioritization Demystified - My Blog January 3rd, 2023

[…] 瞭解更多 […]

4.Andrew January 3rd, 2023

“注意:這就是我反對人們總說什麼H2和H3允許並行傳送多個資源的理由,因為這根本就不叫真正的並行!H1反而比H2/H3並行得多,因為前者有6個獨立連線。充其量,H2/3資料只能算線上路上交錯或多路複用。”

其實這跟H1並沒有區別。假定客戶端有一條網際網路連線,來自這6個“獨立”H1連線的資料包必須在這條線路上交錯,以便沿單一通道傳輸。二者的不同之處在於:H1上的序列化是由我們無法控制的下一跳路由器在無形中完成的,而H2/H3則是通過客戶端和伺服器間的協作端到端完成的。