0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

QUIC是如何解決TCP隊(duì)頭阻塞問(wèn)題的

xCb1_yikoulinux ? 來(lái)源:小林coding ? 作者:小林coding ? 2022-06-14 15:01 ? 次閱讀
有位讀者字節(jié)一面的時(shí)候被問(wèn)到:如何基于 UDP 協(xié)議實(shí)現(xiàn)可靠傳輸?

很多同學(xué)第一反應(yīng)就會(huì)說(shuō)把 TCP 可靠傳輸?shù)奶匦裕ㄐ蛄刑?hào)、確認(rèn)應(yīng)答、超時(shí)重傳、流量控制、擁塞控制)在應(yīng)用層實(shí)現(xiàn)一遍。

實(shí)現(xiàn)的思路確實(shí)這樣沒(méi)錯(cuò),但是有沒(méi)有想過(guò),既然 TCP 天然支持可靠傳輸,為什么還需要基于 UDP 實(shí)現(xiàn)可靠傳輸呢?這不是重復(fù)造輪子嗎?

所以,我們要先弄清楚 TCP 協(xié)議有哪些痛點(diǎn)?而這些痛點(diǎn)是否可以在基于 UDP 協(xié)議實(shí)現(xiàn)的可靠傳輸協(xié)議中得到改進(jìn)?

在之前這篇文章:TCP 就沒(méi)什么缺陷嗎?,我已經(jīng)說(shuō)了 TCP 協(xié)議四個(gè)方面的缺陷:

  • 升級(jí) TCP 的工作很困難;
  • TCP 建立連接的延遲;
  • TCP 存在隊(duì)頭阻塞問(wèn)題;
  • 網(wǎng)絡(luò)遷移需要重新建立 TCP 連接;

現(xiàn)在市面上已經(jīng)有基于 UDP 協(xié)議實(shí)現(xiàn)的可靠傳輸協(xié)議的成熟方案了,那就是 QUIC 協(xié)議,已經(jīng)應(yīng)用在了 HTTP/3。

這次,聊聊 QUIC 是如何實(shí)現(xiàn)可靠傳輸?shù)模坑质侨绾谓鉀Q上面 TCP 協(xié)議四個(gè)方面的缺陷?

QUIC 是如何實(shí)現(xiàn)可靠傳輸?shù)模?/span>

要基于 UDP 實(shí)現(xiàn)的可靠傳輸協(xié)議,那么就要在應(yīng)用層下功夫,也就是要設(shè)計(jì)好協(xié)議的頭部字段。

拿 HTTP/3 舉例子,在 UDP 報(bào)文頭部與 HTTP 消息之間,共有 3 層頭部:

5926bc4e-ebaa-11ec-ba43-dac502259ad0.png

整體看的視角是這樣的:

594ea11e-ebaa-11ec-ba43-dac502259ad0.png

接下來(lái),分別對(duì)每一個(gè) Header 做個(gè)介紹。

Packet Header

Packet Header 首次建立連接時(shí)和日常傳輸數(shù)據(jù)時(shí)使用的 Header 是不同的。如下圖,注意我沒(méi)有把 Header 所有字段都畫(huà)出來(lái),只是畫(huà)出了重要的字段:

595bded8-ebaa-11ec-ba43-dac502259ad0.jpgPacket Header

細(xì)分這兩種:

  • Long Packet Header 用于首次建立連接。
  • Short Packet Header 用于日常傳輸數(shù)據(jù)。

QUIC 也是需要三次握手來(lái)建立連接的,主要目的是為了確定連接 ID。

建立連接時(shí),連接 ID 是由服務(wù)器根據(jù)客戶端的 Source Connection ID 字段生成的,這樣后續(xù)傳輸時(shí),雙方只需要固定住 Destination Connection ID(連接 ID ),從而實(shí)現(xiàn)連接遷移功能。所以,你可以看到日常傳輸數(shù)據(jù)的 Short Packet Header 不需要在傳輸 Source Connection ID 字段了。

Short Packet Header 中的 Packet Number 是每個(gè)報(bào)文獨(dú)一無(wú)二的編號(hào),它是嚴(yán)格遞增的,也就是說(shuō)就算 Packet N 丟失了,重傳的 Packet N 的 Packet Number 已經(jīng)不是 N,而是一個(gè)比 N 大的值。

598189c6-ebaa-11ec-ba43-dac502259ad0.jpg

為什么要這么設(shè)計(jì)呢?

我們先來(lái)看看 TCP 的問(wèn)題,TCP 在重傳報(bào)文時(shí)的序列號(hào)和原始報(bào)文的序列號(hào)是一樣的,也正是由于這個(gè)特性,引入了 TCP 重傳的歧義問(wèn)題。

599ca580-ebaa-11ec-ba43-dac502259ad0.jpgTCP 重傳的歧義問(wèn)題

比如上圖,當(dāng) TCP 發(fā)生超時(shí)重傳后,客戶端發(fā)起重傳,然后接收到了服務(wù)端確認(rèn) ACK 。由于客戶端原始報(bào)文和重傳報(bào)文序列號(hào)都是一樣的,那么服務(wù)端針對(duì)這兩個(gè)報(bào)文回復(fù)的都是相同的 ACK。

這樣的話,客戶端就無(wú)法判斷出是原始報(bào)文的響應(yīng)還是重傳報(bào)文的響應(yīng),這樣在計(jì)算 RTT(往返時(shí)間) 時(shí)應(yīng)該選擇從發(fā)送原始報(bào)文開(kāi)始計(jì)算,還是重傳原始報(bào)文開(kāi)始計(jì)算呢?

  • 如果算成原始報(bào)文的響應(yīng),但實(shí)際上是重傳報(bào)文的響應(yīng)(上圖),會(huì)導(dǎo)致采樣 RTT 變大;
  • 如果算成重傳報(bào)文的響應(yīng),但實(shí)際上是原始報(bào)文的響應(yīng)(上圖),又很容易導(dǎo)致采樣 RTT 過(guò)?。?/li>

RTT 計(jì)算不精確的話,那么 RTO (超時(shí)時(shí)間)也就不精確,因?yàn)?RTO 是基于 RTT 來(lái)計(jì)算的,RTO 計(jì)算不準(zhǔn)確可能導(dǎo)致重傳的概率事件增大。

QUIC 報(bào)文中的 Pakcet Number 是嚴(yán)格遞增的, 即使是重傳報(bào)文,它的 Pakcet Number 也是遞增的,這樣就能更加精確計(jì)算出報(bào)文的 RTT。

59b18306-ebaa-11ec-ba43-dac502259ad0.jpg

如果 ACK 的 Packet Number 是 N+M,就根據(jù)重傳報(bào)文計(jì)算采樣 RTT。如果 ACK 的 Pakcet Number 是 N,就根據(jù)原始報(bào)文的時(shí)間計(jì)算采樣 RTT,沒(méi)有歧義性的問(wèn)題。

另外,還有一個(gè)好處,QUIC 使用的 Packet Number 單調(diào)遞增的設(shè)計(jì),可以讓數(shù)據(jù)包不再像TCP 那樣必須有序確認(rèn),QUIC 支持亂序確認(rèn),當(dāng)數(shù)據(jù)包Packet N 丟失后,只要有新的已接收數(shù)據(jù)包確認(rèn),當(dāng)前窗口就會(huì)繼續(xù)向右滑動(dòng)。

待發(fā)送端超過(guò)一定時(shí)間沒(méi)收到 Packet N 的確認(rèn)報(bào)文后,會(huì)將需要重傳的數(shù)據(jù)包放到待發(fā)送隊(duì)列,重新編號(hào)比如數(shù)據(jù)包 Packet N+M 后重新發(fā)送給接收端,對(duì)重傳數(shù)據(jù)包的處理跟發(fā)送新的數(shù)據(jù)包類(lèi)似,這樣就不會(huì)因?yàn)閬G包重傳將當(dāng)前窗口阻塞在原地,從而解決了隊(duì)頭阻塞問(wèn)題。

所以,Packet Number 單調(diào)遞增的兩個(gè)好處:

  • 可以更加精確計(jì)算 RTT,沒(méi)有 TCP 重傳的歧義性問(wèn)題;
  • 可以支持亂序確認(rèn),防止因?yàn)閬G包重傳將當(dāng)前窗口阻塞在原地,而 TCP 必須是順序確認(rèn)的,丟包時(shí)會(huì)導(dǎo)致窗口不滑動(dòng);

QUIC Frame Header

一個(gè) Packet 報(bào)文中可以存放多個(gè) QUIC Frame。

59bcb4ce-ebaa-11ec-ba43-dac502259ad0.png

每一個(gè) Frame 都有明確的類(lèi)型,針對(duì)類(lèi)型的不同,功能也不同,自然格式也不同。我這里只舉例 Stream 類(lèi)型的 Frame 格式,Stream 可以認(rèn)為就是一條 HTTP 請(qǐng)求,它長(zhǎng)這樣:

59dd8afa-ebaa-11ec-ba43-dac502259ad0.jpg
  • Stream ID 作用:多個(gè)并發(fā)傳輸?shù)?HTTP 消息,通過(guò)不同的 Stream ID 加以區(qū)別;
  • Offset 作用:類(lèi)似于 TCP 協(xié)議中的 Seq 序號(hào),保證數(shù)據(jù)的順序性和可靠性;
  • Length 作用:指明了 Frame 數(shù)據(jù)的長(zhǎng)度。

在前面介紹 Packet Header 時(shí),說(shuō)到 Packet Number 是嚴(yán)格遞增,即使重傳報(bào)文的 Packet Number 也是遞增的,既然重傳數(shù)據(jù)包的 Packet N+M 與丟失數(shù)據(jù)包的 Packet N 編號(hào)并不一致,我們?cè)趺创_定這兩個(gè)數(shù)據(jù)包的內(nèi)容一樣呢?

所以引入 Frame Header 這一層,通過(guò) Stream ID + Offset 字段信息實(shí)現(xiàn)數(shù)據(jù)的有序性,通過(guò)比較兩個(gè)數(shù)據(jù)包的 Stream ID 與 Stream Offset ,如果都是一致,就說(shuō)明這兩個(gè)數(shù)據(jù)包的內(nèi)容一致。

舉個(gè)例子,下圖中,數(shù)據(jù)包 Packet N 丟失了,后面重傳該數(shù)據(jù)包的編號(hào)為 Packet N+2,丟失的數(shù)據(jù)包和重傳的數(shù)據(jù)包 Stream ID 與 Offset 都一致,說(shuō)明這兩個(gè)數(shù)據(jù)包的內(nèi)容一致。這些數(shù)據(jù)包傳輸?shù)浇邮斩撕?,接收端能根?jù) Stream ID 與 Offset 字段信息將 Stream x 和 Stream x+y 按照順序組織起來(lái),然后交給應(yīng)用程序處理。

59e937d8-ebaa-11ec-ba43-dac502259ad0.jpg

總的來(lái)說(shuō),QUIC 通過(guò)單向遞增的 Packet Number,配合 Stream ID 與 Offset 字段信息,可以支持亂序確認(rèn)而不影響數(shù)據(jù)包的正確組裝,擺脫了TCP 必須按順序確認(rèn)應(yīng)答 ACK 的限制,解決了 TCP 因某個(gè)數(shù)據(jù)包重傳而阻塞后續(xù)所有待發(fā)送數(shù)據(jù)包的問(wèn)題。

QUIC 是如何解決 TCP 隊(duì)頭阻塞問(wèn)題的?

什么是 TCP 隊(duì)頭阻塞問(wèn)題?

TCP 隊(duì)頭阻塞的問(wèn)題要從兩個(gè)角度看,一個(gè)是發(fā)送窗口的隊(duì)頭阻塞,另外一個(gè)是接收窗口的隊(duì)頭阻塞

先來(lái)說(shuō)說(shuō)發(fā)送窗口的隊(duì)頭阻塞。

TCP 發(fā)送出去的數(shù)據(jù),都是需要按序確認(rèn)的,只有在數(shù)據(jù)都被按順序確認(rèn)完后,發(fā)送窗口才會(huì)往前滑動(dòng)。

舉個(gè)例子,比如下圖的發(fā)送方把發(fā)送窗口內(nèi)的數(shù)據(jù)全部都發(fā)出去了,可用窗口的大小就為 0 了,表明可用窗口耗盡,在沒(méi)收到 ACK 確認(rèn)之前是無(wú)法繼續(xù)發(fā)送數(shù)據(jù)了。

5a4a9794-ebaa-11ec-ba43-dac502259ad0.png可用窗口耗盡

接著,當(dāng)發(fā)送方收到對(duì)第 32~36 字節(jié)的 ACK 確認(rèn)應(yīng)答后,則滑動(dòng)窗口往右邊移動(dòng) 5 個(gè)字節(jié),因?yàn)橛?5 個(gè)字節(jié)的數(shù)據(jù)被應(yīng)答確認(rèn),接下來(lái)第 52~56 字節(jié)又變成了可用窗口,那么后續(xù)也就可以發(fā)送 52~56 這 5 個(gè)字節(jié)的數(shù)據(jù)了。

5a61f966-ebaa-11ec-ba43-dac502259ad0.png32 ~ 36 字節(jié)已確認(rèn)

但是如果某個(gè)數(shù)據(jù)報(bào)文丟失或者其對(duì)應(yīng)的 ACK 報(bào)文在網(wǎng)絡(luò)中丟失,會(huì)導(dǎo)致發(fā)送方無(wú)法移動(dòng)發(fā)送窗口,這時(shí)就無(wú)法再發(fā)送新的數(shù)據(jù),只能超時(shí)重傳這個(gè)數(shù)據(jù)報(bào)文,直到收到這個(gè)重傳報(bào)文的 ACK,發(fā)送窗口才會(huì)移動(dòng),繼續(xù)后面的發(fā)送行為。

舉個(gè)例子,比如下圖,客戶端是發(fā)送方,服務(wù)器是接收方。

5ab52a96-ebaa-11ec-ba43-dac502259ad0.jpg

客戶端發(fā)送了第 5~9 字節(jié)的數(shù)據(jù),但是第 5 字節(jié)的 ACK 確認(rèn)報(bào)文在網(wǎng)絡(luò)中丟失了,那么即使客戶端收到第 6~9 字節(jié)的 ACK 確認(rèn)報(bào)文,發(fā)送窗口也不會(huì)往前移動(dòng)。

此時(shí)的第 5 字節(jié)相當(dāng)于“隊(duì)頭”,因?yàn)闆](méi)有收到“隊(duì)頭”的 ACK 確認(rèn)報(bào)文,導(dǎo)致發(fā)送窗口無(wú)法往前移動(dòng),此時(shí)發(fā)送方就無(wú)法繼續(xù)發(fā)送后面的數(shù)據(jù),相當(dāng)于按下了發(fā)送行為的暫停鍵,這就是發(fā)送窗口的隊(duì)頭阻塞問(wèn)題。

再來(lái)說(shuō)說(shuō)接收窗口的隊(duì)頭阻塞。

接收方收到的數(shù)據(jù)范圍必須在接收窗口范圍內(nèi),如果收到超過(guò)接收窗口范圍的數(shù)據(jù),就會(huì)丟棄該數(shù)據(jù),比如下圖接收窗口的范圍是 32 ~ 51 字節(jié),如果收到第 52 字節(jié)以上數(shù)據(jù)都會(huì)被丟棄。

5ac03e40-ebaa-11ec-ba43-dac502259ad0.png接收窗口

接收窗口什么時(shí)候才能滑動(dòng)?當(dāng)接收窗口收到有序數(shù)據(jù)時(shí),接收窗口才能往前滑動(dòng),然后那些已經(jīng)接收并且被確認(rèn)的「有序」數(shù)據(jù)就可以被應(yīng)用層讀取。

但是,當(dāng)接收窗口收到的數(shù)據(jù)不是有序的,比如收到第 33~40 字節(jié)的數(shù)據(jù),由于第 32 字節(jié)數(shù)據(jù)沒(méi)有收到, 接收窗口無(wú)法向前滑動(dòng),那么即使先收到第 33~40 字節(jié)的數(shù)據(jù),這些數(shù)據(jù)也無(wú)法被應(yīng)用層讀取的。只有當(dāng)發(fā)送方重傳了第 32 字節(jié)數(shù)據(jù)并且被接收方收到后,接收窗口才會(huì)往前滑動(dòng),然后應(yīng)用層才能從內(nèi)核讀取第 32~40 字節(jié)的數(shù)據(jù)。

好了,至此發(fā)送窗口和接收窗口的隊(duì)頭阻塞問(wèn)題都說(shuō)完了,這兩個(gè)問(wèn)題的原因都是因?yàn)?TCP 必須按序處理數(shù)據(jù),也就是 TCP 層為了保證數(shù)據(jù)的有序性,只有在處理完有序的數(shù)據(jù)后,滑動(dòng)窗口才能往前滑動(dòng),否則就停留。

  • 停留「發(fā)送窗口」會(huì)使得發(fā)送方無(wú)法繼續(xù)發(fā)送數(shù)據(jù)。

  • 停留「接收窗口」會(huì)使得應(yīng)用層無(wú)法讀取新的數(shù)據(jù)。

其實(shí)也不能怪 TCP 協(xié)議,它本來(lái)設(shè)計(jì)目的就是為了保證數(shù)據(jù)的有序性。

HTTP/2 的隊(duì)頭阻塞

HTTP/2 通過(guò)抽象出 Stream 的概念,實(shí)現(xiàn)了 HTTP 并發(fā)傳輸,一個(gè) Stream 就代表 HTTP/1.1 里的請(qǐng)求和響應(yīng)。

5af01afc-ebaa-11ec-ba43-dac502259ad0.pngHTTP/2

在 HTTP/2 連接上,不同 Stream 的幀是可以亂序發(fā)送的(因此可以并發(fā)不同的 Stream ),因?yàn)槊總€(gè)幀的頭部會(huì)攜帶 Stream ID 信息,所以接收端可以通過(guò) Stream ID 有序組裝成 HTTP 消息,而同一 Stream 內(nèi)部的幀必須是嚴(yán)格有序的。

但是 HTTP/2 多個(gè) Stream 請(qǐng)求都是在一條 TCP 連接上傳輸,這意味著多個(gè) Stream 共用同一個(gè) TCP 滑動(dòng)窗口,那么當(dāng)發(fā)生數(shù)據(jù)丟失,滑動(dòng)窗口是無(wú)法往前移動(dòng)的,此時(shí)就會(huì)阻塞住所有的 HTTP 請(qǐng)求,這屬于 TCP 層隊(duì)頭阻塞

5aff00c6-ebaa-11ec-ba43-dac502259ad0.jpg

沒(méi)有隊(duì)頭阻塞的 QUIC

QUIC 也借鑒 HTTP/2 里的 Stream 的概念,在一條 QUIC 連接上可以并發(fā)發(fā)送多個(gè) HTTP 請(qǐng)求 (Stream)。

但是 QUIC 給每一個(gè) Stream 都分配了一個(gè)獨(dú)立的滑動(dòng)窗口,這樣使得一個(gè)連接上的多個(gè) Stream 之間沒(méi)有依賴(lài)關(guān)系,都是相互獨(dú)立的,各自控制的滑動(dòng)窗口

假如 Stream2 丟了一個(gè) UDP 包,也只會(huì)影響 Stream2 的處理,不會(huì)影響其他 Stream,與 HTTP/2 不同,HTTP/2 只要某個(gè)流中的數(shù)據(jù)包丟失了,其他流也會(huì)因此受影響。

5b4a218c-ebaa-11ec-ba43-dac502259ad0.jpg

QUIC 是如何做流量控制的?

TCP 流量控制是通過(guò)讓「接收方」告訴「發(fā)送方」,它(接收方)的接收窗口有多大,從而讓「發(fā)送方」根據(jù)「接收方」的實(shí)際接收能力控制發(fā)送的數(shù)據(jù)量。

在前面說(shuō)到,TCP 的接收窗口在收到有序的數(shù)據(jù)后,接收窗口才能往前滑動(dòng),否則停止滑動(dòng);TCP 的發(fā)送窗口在收到對(duì)已發(fā)送數(shù)據(jù)的順序確認(rèn) ACK后,發(fā)送窗口才能往前滑動(dòng),否則停止滑動(dòng)。

QUIC 是基于 UDP 傳輸?shù)?,?UDP 沒(méi)有流量控制,因此 QUIC 實(shí)現(xiàn)了自己的流量控制機(jī)制。不過(guò),QUIC 的滑動(dòng)窗口滑動(dòng)的條件跟 TCP 有所差別的。

QUIC 實(shí)現(xiàn)了兩種級(jí)別的流量控制,分別為 Stream 和 Connection 兩種級(jí)別:

  • Stream 級(jí)別的流量控制:每個(gè) Stream 都有獨(dú)立的滑動(dòng)窗口,所以每個(gè) Stream 都可以做流量控制,防止單個(gè) Stream 消耗連接(Connection)的全部接收緩沖。
  • Connection 流量控制:限制連接中所有 Stream 相加起來(lái)的總字節(jié)數(shù),防止發(fā)送方超過(guò)連接的緩沖容量。

Stream 級(jí)別的流量控制

回想一下 TCP,當(dāng)發(fā)送方發(fā)送 seq1、seq2、seq3 報(bào)文,由于 seq2 報(bào)文丟失了,接收方收到 seq1 后會(huì) ack1,然后接收方收到 seq3 后還是回 ack1(因?yàn)闆](méi)有收到 seq2),這時(shí)發(fā)送窗口無(wú)法往前滑動(dòng)。

但是,QUIC 就不一樣了,即使中途有報(bào)文丟失,發(fā)送窗口依然可以往前滑動(dòng),具體怎么做到的呢?我們來(lái)看看。

最開(kāi)始,接收方的接收窗口初始狀態(tài)如下:

5b80a20c-ebaa-11ec-ba43-dac502259ad0.png

接著,接收方收到了發(fā)送方發(fā)送過(guò)來(lái)的數(shù)據(jù),有的數(shù)據(jù)被上層讀取了,有的數(shù)據(jù)丟包了,此時(shí)的接收窗口狀況如下:

5ba95008-ebaa-11ec-ba43-dac502259ad0.png

可以看到,接收窗口的左邊界取決于接收到的最大偏移字節(jié)數(shù),此時(shí)的接收窗口 = 最大窗口數(shù) - 接收到的最大偏移數(shù),這里就跟 TCP 不一樣了。

那接收窗口觸發(fā)的滑動(dòng)條件是什么呢?看下圖:

5bb2f824-ebaa-11ec-ba43-dac502259ad0.png接收窗口觸發(fā)的滑動(dòng)

當(dāng)圖中的綠色部分?jǐn)?shù)據(jù)超過(guò)最大接收窗口的一半后,最大接收窗口向右移動(dòng),同時(shí)給對(duì)端發(fā)送「窗口更新幀」。當(dāng)發(fā)送方收到接收方的窗口更新幀后,發(fā)送窗口也會(huì)往前滑動(dòng),即使中途有丟包,依然也會(huì)滑動(dòng),這樣就防止像 TCP 那樣在出現(xiàn)丟包的時(shí)候,導(dǎo)致發(fā)送窗口無(wú)法移動(dòng),從而避免了無(wú)法繼續(xù)發(fā)送數(shù)據(jù)。

在前面我們說(shuō)過(guò),每個(gè) Stream 都有各自的滑動(dòng)窗口,不同 Stream 互相獨(dú)立,隊(duì)頭的 Stream A 被阻塞后,不妨礙 StreamB、C的讀取。而對(duì)于 TCP 而言,其不知道將不同的 Stream 交給上層哪一個(gè)請(qǐng)求,因此同一個(gè)Connection內(nèi),Stream A 被阻塞后,StreamB、C 必須等待。

經(jīng)過(guò)了解完 QUIC 的流量控制機(jī)制后,對(duì)于隊(duì)頭阻塞問(wèn)題解決得更加徹底。

QUIC 協(xié)議中同一個(gè) Stream 內(nèi),滑動(dòng)窗口的移動(dòng)僅取決于接收到的最大字節(jié)偏移(盡管期間可能有部分?jǐn)?shù)據(jù)未被接收),而對(duì)于 TCP 而言,窗口滑動(dòng)必須保證此前的 packet 都有序的接收到了,其中一個(gè) packet 丟失就會(huì)導(dǎo)致窗口等待。

Connection 流量控制

而對(duì)于 Connection 級(jí)別的流量窗口,其接收窗口大小就是各個(gè) Stream 接收窗口大小之和。

5bfbe6ce-ebaa-11ec-ba43-dac502259ad0.pngConnection 流量控制

上圖所示的例子,所有 Streams 的最大窗口數(shù)為 120,其中:

  • Stream 1 的最大接收偏移為 100,可用窗口 = 120 - 100 = 20
  • Stream 2 的最大接收偏移為 90,可用窗口 = 120 - 90 = 30
  • Stream 3 的最大接收偏移為 110,可用窗口 = 120 - 110 = 10

那么整個(gè) Connection 的可用窗口 = 20 + 30 + 10 = 60

可用窗口 = Stream 1 可用窗口 + Stream 2 可用窗口 + Stream 3 可用窗口

QUIC 對(duì)擁塞控制改進(jìn)

QUIC 協(xié)議當(dāng)前默認(rèn)使用了 TCP 的 Cubic 擁塞控制算法(我們熟知的慢開(kāi)始、擁塞避免、快重傳、快恢復(fù)策略),同時(shí)也支持 CubicBytes、Reno、RenoBytes、BBR、PCC 等擁塞控制算法,相當(dāng)于將 TCP 的擁塞控制算法照搬過(guò)來(lái)了,QUIC 是如何改進(jìn) TCP 的擁塞控制算法的呢?

QUIC 是處于應(yīng)用層的,應(yīng)用程序?qū)用婢湍軐?shí)現(xiàn)不同的擁塞控制算法,不需要操作系統(tǒng),不需要內(nèi)核支持。這是一個(gè)飛躍,因?yàn)閭鹘y(tǒng)的 TCP 擁塞控制,必須要端到端的網(wǎng)絡(luò)協(xié)議棧支持,才能實(shí)現(xiàn)控制效果。而內(nèi)核和操作系統(tǒng)的部署成本非常高,升級(jí)周期很長(zhǎng),所以 TCP 擁塞控制算法迭代速度是很慢的。而 QUIC 可以隨瀏覽器更新,QUIC 的擁塞控制算法就可以有較快的迭代速度。

TCP 更改擁塞控制算法是對(duì)系統(tǒng)中所有應(yīng)用都生效,無(wú)法根據(jù)不同應(yīng)用設(shè)定不同的擁塞控制策略。但是因?yàn)?QUIC 處于應(yīng)用層,所以就可以針對(duì)不同的應(yīng)用設(shè)置不同的擁塞控制算法,這樣靈活性就很高了。

QUIC 更快的連接建立

對(duì)于 HTTP/1 和 HTTP/2 協(xié)議,TCP 和 TLS 是分層的,分別屬于內(nèi)核實(shí)現(xiàn)的傳輸層、openssl 庫(kù)實(shí)現(xiàn)的表示層,因此它們難以合并在一起,需要分批次來(lái)握手,先 TCP 握手(1RTT),再 TLS 握手(2RTT),所以需要 3RTT 的延遲才能傳輸數(shù)據(jù),就算 Session 會(huì)話服用,也需要至少 2 個(gè) RTT。

HTTP/3 在傳輸數(shù)據(jù)前雖然需要 QUIC 協(xié)議握手,這個(gè)握手過(guò)程只需要 1 RTT,握手的目的是為確認(rèn)雙方的「連接 ID」,連接遷移就是基于連接 ID 實(shí)現(xiàn)的。

但是 HTTP/3 的 QUIC 協(xié)議并不是與 TLS 分層,而是QUIC 內(nèi)部包含了 TLS,它在自己的幀會(huì)攜帶 TLS 里的“記錄”,再加上 QUIC 使用的是 TLS1.3,因此僅需 1 個(gè) RTT 就可以「同時(shí)」完成建立連接與密鑰協(xié)商,甚至在第二次連接的時(shí)候,應(yīng)用數(shù)據(jù)包可以和 QUIC 握手信息(連接信息 + TLS 信息)一起發(fā)送,達(dá)到 0-RTT 的效果

如下圖右邊部分,HTTP/3 當(dāng)會(huì)話恢復(fù)時(shí),有效負(fù)載數(shù)據(jù)與第一個(gè)數(shù)據(jù)包一起發(fā)送,可以做到 0-RTT:

5c0bf334-ebaa-11ec-ba43-dac502259ad0.png

QUIC 是如何遷移連接的?

基于 TCP 傳輸協(xié)議的 HTTP 協(xié)議,由于是通過(guò)四元組(源 IP、源端口、目的 IP、目的端口)確定一條 TCP 連接。

5c485b08-ebaa-11ec-ba43-dac502259ad0.png圖片

那么當(dāng)移動(dòng)設(shè)備的網(wǎng)絡(luò)從 4G 切換到 WIFI 時(shí),意味著 IP 地址變化了,那么就必須要斷開(kāi)連接,然后重新建立 TCP 連接

而建立連接的過(guò)程包含 TCP 三次握手和 TLS 四次握手的時(shí)延,以及 TCP 慢啟動(dòng)的減速過(guò)程,給用戶的感覺(jué)就是網(wǎng)絡(luò)突然卡頓了一下,因此連接的遷移成本是很高的。

QUIC 協(xié)議沒(méi)有用四元組的方式來(lái)“綁定”連接,而是通過(guò)連接 ID來(lái)標(biāo)記通信的兩個(gè)端點(diǎn),客戶端和服務(wù)器可以各自選擇一組 ID 來(lái)標(biāo)記自己,因此即使移動(dòng)設(shè)備的網(wǎng)絡(luò)變化后,導(dǎo)致 IP 地址變化了,只要仍保有上下文信息(比如連接 ID、TLS 密鑰等),就可以“無(wú)縫”地復(fù)用原連接,消除重連的成本,沒(méi)有絲毫卡頓感,達(dá)到了連接遷移的功能。


原文標(biāo)題:字節(jié)一面:如何用 UDP 實(shí)現(xiàn)可靠傳輸?

文章出處:【微信公眾號(hào):一口Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • TCP
    TCP
    +關(guān)注

    關(guān)注

    8

    文章

    1324

    瀏覽量

    78754
  • UDP
    UDP
    +關(guān)注

    關(guān)注

    0

    文章

    317

    瀏覽量

    33801
  • 阻塞
    +關(guān)注

    關(guān)注

    0

    文章

    24

    瀏覽量

    8069
  • Quic
    +關(guān)注

    關(guān)注

    0

    文章

    25

    瀏覽量

    7262

原文標(biāo)題:字節(jié)一面:如何用 UDP 實(shí)現(xiàn)可靠傳輸?

文章出處:【微信號(hào):yikoulinux,微信公眾號(hào):一口Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    socket阻塞和非阻塞的區(qū)別是什么

    在計(jì)算機(jī)編程中,socket 是一種通信端點(diǎn),用于在網(wǎng)絡(luò)中進(jìn)行數(shù)據(jù)傳輸。Socket 可以是阻塞的或非阻塞的,這兩種模式在處理數(shù)據(jù)傳輸時(shí)有不同的行為。 阻塞模式(Blocking Mode) 在
    的頭像 發(fā)表于 08-16 11:13 ?263次閱讀

    esp8266讀取模擬數(shù)據(jù)并記錄到eeprom,發(fā)送tcp包時(shí)無(wú)法讀取模擬如何解決?

    嗨,esp8266 讀取模擬數(shù)據(jù)并記錄到 eeprom,我正在將存儲(chǔ)在 eeprom 中的數(shù)據(jù)作為 tcp 包發(fā)送,但在發(fā)送 tcp 包時(shí)無(wú)法讀取模擬,如何解決它? 如何將線程用于這些作業(yè)?
    發(fā)表于 07-11 07:22

    有沒(méi)有辦法控制TCP連接超時(shí)?

    有沒(méi)有辦法控制TCP連接超時(shí)?似乎在 SDK pdf 的任何地方都找不到它。 我堅(jiān)持使用 1.3.0,但 2.1.2 也沒(méi)有。 通常,我會(huì)將套接字置于非阻塞模式,但我也不知道如何使用 1.3.0 SDK 執(zhí)行此操作。
    發(fā)表于 07-10 06:29

    如何同時(shí)在ESP8266上運(yùn)行TCP客戶端和TCP服務(wù)?

    客戶端無(wú)法連接到 TCP 服務(wù)器。如果不將 TCP 客戶端從 ESP 連接到云服務(wù)器,則 ESP 上的 TCP 服務(wù)器可以很好地接受 TCP 客戶端連接。
    發(fā)表于 07-08 08:26

    使用Lwip非阻塞tcp socket時(shí),能同時(shí)運(yùn)行tcp socket和https服務(wù)嗎?

    現(xiàn)在我正使用lwip的非阻塞socket作為tcp通信手段,然后在此過(guò)程中,進(jìn)行https的ota操作,然后發(fā)現(xiàn)出現(xiàn)socket read fail問(wèn)題 并且https也無(wú)法使用,若將當(dāng)前
    發(fā)表于 06-07 06:31

    隊(duì)攻防之快速打點(diǎn)

    導(dǎo)讀: 在整個(gè)紅隊(duì)攻防體系中,打點(diǎn)是最基礎(chǔ)也是最重要的一步。它對(duì)于紅隊(duì)在攻防比賽中取得快速和高效的進(jìn)展至關(guān)重要。然而,在實(shí)際的攻防比賽中,由于資產(chǎn)數(shù)量龐大、紅隊(duì)人員稀缺以及時(shí)間緊迫等各種因素,導(dǎo)致
    的頭像 發(fā)表于 05-27 10:20 ?162次閱讀
    紅<b class='flag-5'>隊(duì)</b>攻防之快速打點(diǎn)

    什么是阻塞和非阻塞?

    什么是阻塞和非阻塞?我們就用管道的讀寫(xiě)來(lái)舉例子。
    的頭像 發(fā)表于 03-25 10:04 ?374次閱讀

    verilog同步和異步的區(qū)別 verilog阻塞賦值和非阻塞賦值的區(qū)別

    Verilog是一種硬件描述語(yǔ)言,用于設(shè)計(jì)和模擬數(shù)字電路。在Verilog中,同步和異步是用來(lái)描述數(shù)據(jù)傳輸和信號(hào)處理的兩種不同方式,而阻塞賦值和非阻塞賦值是兩種不同的賦值方式。本文將詳細(xì)解釋
    的頭像 發(fā)表于 02-22 15:33 ?1175次閱讀

    網(wǎng)宿基于QUIC的技術(shù)方案實(shí)踐

    網(wǎng)宿基于業(yè)務(wù)場(chǎng)景和網(wǎng)絡(luò)環(huán)境的實(shí)戰(zhàn)也發(fā)現(xiàn),QUIC優(yōu)化效果明顯。以直播業(yè)務(wù)為例,使用同一服務(wù)器,推兩路1M碼率的直播流到同一邊緣節(jié)點(diǎn),在丟包20%的情況下,QUIC的流暢度比TCP高20%,首包時(shí)間比
    發(fā)表于 12-05 13:56 ?338次閱讀
    網(wǎng)宿基于<b class='flag-5'>QUIC</b>的技術(shù)方案實(shí)踐

    什么事件會(huì)使執(zhí)行變成阻塞

    執(zhí)行阻塞是指當(dāng)一個(gè)進(jìn)程無(wú)法繼續(xù)執(zhí)行時(shí)被掛起的狀態(tài)。這可以由多種事件引起,下面詳細(xì)介紹了一些常見(jiàn)的情況: I/O操作阻塞:在進(jìn)行文件讀寫(xiě)、網(wǎng)絡(luò)通信、數(shù)據(jù)庫(kù)訪問(wèn)等I/O操作時(shí),如果所需的數(shù)據(jù)還沒(méi)有
    的頭像 發(fā)表于 11-17 14:08 ?673次閱讀

    阻塞態(tài)可以直接到運(yùn)行態(tài)嗎

    阻塞態(tài)即是指進(jìn)程或線程在等待某種事件或資源時(shí)暫時(shí)停止執(zhí)行的狀態(tài)。在計(jì)算機(jī)系統(tǒng)中,由于各種原因,進(jìn)程或線程可能會(huì)進(jìn)入阻塞態(tài),等待著能夠繼續(xù)執(zhí)行的條件成熟。 在絕大多數(shù)情況下,阻塞態(tài)到運(yùn)行態(tài)并不是直接
    的頭像 發(fā)表于 11-17 11:43 ?1777次閱讀

    阻塞的的connect()函數(shù)如何編寫(xiě)

    由于網(wǎng)絡(luò)編程涉及很多細(xì)節(jié)和技巧,一直想寫(xiě)篇文章來(lái)總結(jié)下這方面的心得與經(jīng)驗(yàn),希望對(duì)來(lái)者有一點(diǎn)幫助,那就善莫大焉了。 一、非阻塞的的connect()函數(shù)如何編寫(xiě) 我們知道用connect()函數(shù)默認(rèn)
    的頭像 發(fā)表于 11-11 16:23 ?1121次閱讀
    非<b class='flag-5'>阻塞</b>的的connect()函數(shù)如何編寫(xiě)

    什么是阻塞?怎么設(shè)計(jì)才能滿足阻塞指標(biāo)?

    阻塞就是外部有阻塞干擾信號(hào)的時(shí)候,設(shè)備還可以正常運(yùn)行。一般分為帶內(nèi)阻塞和帶外阻塞,由于直放站都是做寬帶設(shè)備,一般只提帶外阻塞。
    的頭像 發(fā)表于 10-10 11:22 ?1367次閱讀

    網(wǎng)絡(luò)IO模型:阻塞與非阻塞

    阻塞 IO 模型 在Linux ,默認(rèn)情況下所有的 socket 都是阻塞的,一個(gè)典型的讀操作流程如圖所示。 阻塞和非阻塞的概念描述的是用戶線程調(diào)用內(nèi)核 IO 操作的方式:
    的頭像 發(fā)表于 10-08 17:16 ?719次閱讀
    網(wǎng)絡(luò)IO模型:<b class='flag-5'>阻塞</b>與非<b class='flag-5'>阻塞</b>

    MQTT over QUIC:EMQ 攜手英特爾、上海交大與全球名校共同探索下一代物聯(lián)網(wǎng)協(xié)議

    MQTT over QUIC 將傳統(tǒng) MQTT 協(xié)議中基于 TCP 的傳輸層協(xié)議替換為了 QUIC(Quick UDP Internet Connections)。與 TCP 不同,
    的頭像 發(fā)表于 09-27 17:16 ?1235次閱讀
    MQTT over <b class='flag-5'>QUIC</b>:EMQ 攜手英特爾、上海交大與全球名校共同探索下一代物聯(lián)網(wǎng)協(xié)議