一般咱們提到隊頭阻塞,指的多是TCP協議中的隊頭阻塞,可是HTTP1.1中也有一個相似TCP隊頭阻塞的問題,下面各自介紹一下。瀏覽器
隊頭阻塞(head-of-line blocking)發生在一個TCP分節丟失,致使其後續分節不按序到達接收端的時候。該後續分節將被接收端一直保持直到丟失的第一個分節被髮送端重傳併到達接收端爲止。該後續分節的延遲遞送確保接收應用進程可以按照發送端的發送順序接收數據。這種爲了達到徹底有序而引入的延遲機制很是有用,但也有不利之處。性能優化
假設在單個TCP鏈接上發送語義獨立的消息,好比說服務器可能發送3幅不一樣的圖像供Web瀏覽器顯示。爲了營造這幾幅圖像在用戶屏幕上並行顯示的效果,服務器先發送第一幅圖像的一個斷片,再發送第二幅圖像的一個斷片,而後再發送第三幅圖像的一個斷片;服務器重複這個過程,直到這3幅圖像所有成功地發送到瀏覽器爲止。服務器
要是第一幅圖像的某個斷片內容的TCP分節丟失了,客戶端將保持已到達的不按序的全部數據,直到丟失的分節重傳成功。這樣不只延緩了第一幅圖像數據的遞送,也延緩了第二幅和第三幅圖像數據的遞送。網絡
上面用瀏覽器請求圖片資源舉例子,但實際上HTTP自身也有相似TCP隊頭阻塞的狀況。要介紹HTTP隊頭阻塞,就須要先講講HTTP的管道化(pipelining)。性能
HTTP1.1 容許在持久鏈接上可選的使用請求管道。這是相對於keep-alive鏈接的又一性能優化。在相應到達以前,能夠將多條請求放入隊列,當第一條請求發往服務器的時候,第二第三條請求也能夠開始發送了,在高延時網絡條件下,這樣作能夠下降網絡的環回時間,提升性能。優化
非管道化與管道化的區別示意 ui
在通常狀況下,HTTP遵照「請求-響應」的模式,也就是客戶端每次發送一個請求到服務端,服務端返回響應。這種模式很是容易理解,可是效率並非那麼高,爲了提升速度和效率,人們作了不少嘗試:google
前面提到HTTP管道化要求服務端必須按照請求發送的順序返回響應,那若是一個響應返回延遲了,那麼其後續的響應都會被延遲,直到隊頭的響應送達。cdn
對於HTTP1.1中管道化致使的請求/響應級別的隊頭阻塞,可使用HTTP2解決。HTTP2不使用管道化的方式,而是引入了幀、消息和數據流等概念,每一個請求/響應被稱爲消息,每一個消息都被拆分紅若干個幀進行傳輸,每一個幀都分配一個序號。每一個幀在傳輸是屬於一個數據流,而一個鏈接上能夠存在多個流,各個幀在流和鏈接上獨立傳輸,到達以後在組裝成消息,這樣就避免了請求/響應阻塞。blog
固然,即便使用HTTP2,若是HTTP2底層使用的是TCP協議,仍可能出現TCP隊頭阻塞。
TCP中的隊頭阻塞的產生是由TCP自身的實現機制決定的,沒法避免。想要在應用程序當中避免TCP隊頭阻塞帶來的影響,只有捨棄TCP協議。
好比google推出的quic協議,在某種程度上能夠說避免了TCP中的隊頭阻塞,由於它根本不使用TCP協議,而是在UDP協議的基礎上實現了可靠傳輸。而UDP是面向數據報的協議,數據報之間不會有阻塞約束。
此外還有一個SCTP(流控制傳輸協議),它是和TCP、UDP在同一層次的傳輸協議。SCTP的多流特性也能夠儘量的避免隊頭阻塞的狀況。
從TCP隊頭阻塞和HTTP隊頭阻塞的緣由咱們能夠看到,出現隊頭阻塞的緣由有兩個:
因此要避免隊頭阻塞,就須要從以上兩個方面出發,好比quic協議不使用TCP協議而是使用UDP協議,SCTP協議支持一個鏈接上存在多個數據流等等。