一、什么是隊頭阻塞
隊頭阻塞,在網絡模型中簡單理解就是,對于隊列型的請求模型,如HTTP的請求-響應模型、TCP的ACK確認機制,都依賴得到一個具體的響應包,如果收不到這個響應包,那下一個請求就不能發,從而導致網絡連接的阻塞。
二、HTTP隊頭阻塞
上面說了HTTP的隊頭阻塞原因是1.1的請求-響應模型,同一個連接中,下一個請求需要等上一個響應回來才能發出去;
那就很容易想到兩種方式,要么同時建立多個連接,同時多個連接發送請求;但這樣會有一些問題:
- 導致資源浪費,包括套接字、內存、網絡帶寬等;
- 實現復雜,客戶端和服務器都要維護多個連接的狀態,防止斷開。
所以瀏覽器一般都會限制最大連接數;因此,這個方法能一定程度上解決隊頭阻塞問題,但效果一般。
那既然多個連接行不通,那就想辦法讓多個請求在一個連接上進行,即多組請求-響應復用同一個連接,多路復用技術。
那怎么實現呢?在HTTP2中,是通過把請求格式改造成二進制幀的方式。
客戶端和服務器通過約定streamID的方式,來把同一個連接中,多個請求的stream幀區分組合,得到有效的請求數據。
通過這種方式,不同請求之間就不存在依賴關系了,HTTP2的隊頭阻塞問題也就解決。
三、TCP隊頭阻塞
因為HTTP是基于TCP的,所以對于上面的Stream幀,無論是改變編碼方式、包結構等等方法,對于TCP連接來說,它接收到的都是字節流(沒錯,就是TCP的特性之一,基于字節流傳輸)。
TCP在實際發送連接的過程中,把數據分段傳輸,因此,一個HTTP請求也會被分段發送。而且TCP又是通過序列號來保證可靠傳輸的,必須要前面的數據都收到,服務端才能從緩沖區中完整讀取數據。
因此如果TCP連接中有數據段丟失,那這個請求也就被阻塞了,即TCP的隊頭阻塞。
為了解決TCP隊頭阻塞,編寫HTTP3的人想到了UDP,UDP沒有可靠傳輸,在UDP的基礎上,通過算法保證傳輸的可靠性,即QUIC,讓HTTP3不再被TCP的隊頭阻塞困擾。
四、一些總結
在工作的一年中,接觸了很多網絡相關的問題與實現:
比如,通信協議:HTTP、TCP、QUIC、RPC、WebSocket,還有Socket4代理等等。
也遇到了一些實際的網絡問題,像
- 海外,尤其是東南亞等網絡基建不好的地區,為了解決網絡延遲導致的用戶體驗差而引入QUIC;
- 為了降低網絡連接建立的開銷,引入長連接;
本文就嘗試通過分析隊頭阻塞,也算是做一個簡單的回顧~