影響TCP連接吞吐量的致命因素:HOL
一、什么是HOL
HOL是Head of line blocking的意思,在互聯(lián)網(wǎng)領(lǐng)域,包括HTTP head of line blocking和 TCP head of line blocking。
1. HTTP Head of line blocking
Wikipedia對(duì)HTTP HOL的解釋如下:

雖然HTTP/2解決了HTTP/1.1的HOL問題,但由于是建立在TCP基礎(chǔ)上,所以仍然存在TCP層面的HOL問題。
2. TCP Head of line blocking
TCP HOL定義如下:

例如在TCP接收緩沖區(qū),請(qǐng)求的第一個(gè)數(shù)據(jù)包由于某種原因一直未到達(dá),緩沖區(qū)里面的后續(xù)數(shù)據(jù)包就無法傳遞給上層應(yīng)用,只能處于等待中,直到第一個(gè)數(shù)據(jù)包過來,才能一起傳遞給上層應(yīng)用。
TCP HOL帶來的問題具有普遍性。只要利用TCP,就有這方面的問題,因此影響范圍非常廣泛。
二、案例分析
1. Network switches

上圖展示了網(wǎng)絡(luò)交換機(jī)中不同input隊(duì)列是如何因?yàn)镠OL等待的。
第一個(gè)和第三個(gè)input隊(duì)列,都在競(jìng)爭(zhēng)使用Output 4。如果交換機(jī)選擇傳遞第三個(gè)input隊(duì)列的數(shù)據(jù)包,那么第一個(gè)input隊(duì)列的數(shù)據(jù)包只能選擇等待。第一個(gè)input隊(duì)列中的序號(hào)3數(shù)據(jù)包因?yàn)镠OL只能等待,雖然output 3是空閑的。
2. 單個(gè)連接 vs 多個(gè)連接實(shí)驗(yàn)
下面是并發(fā)為1的吞吐量,為153.60 reqs/sec。

下面是并發(fā)為10的吞吐量,為145.08 reqs/sec。
![]()

這里10個(gè)并發(fā)比1個(gè)并發(fā)吞吐量還低,是因?yàn)闇y(cè)試環(huán)境是docker環(huán)境,硬件配置差所導(dǎo)致。
上面測(cè)試是在無丟包網(wǎng)絡(luò)環(huán)境下進(jìn)行的,那么在網(wǎng)絡(luò)丟包情況下會(huì)怎么樣?
我們模擬丟包率1%的網(wǎng)絡(luò)環(huán)境。
![]()
并發(fā)為1的吞吐量下降為37.41 reqs/sec。

并發(fā)為10的吞吐量為132.20 reqs/sec。

我們發(fā)現(xiàn)在丟包情況下,多個(gè)并發(fā)效果更好。這是因?yàn)槎鄠€(gè)并發(fā)情況下,HOL blocking問題得到了一定的緩解,而單個(gè)連接,則因?yàn)镠OL blocking問題顯得很明顯。
3. tcpcopy和intercept交互
很長(zhǎng)一段時(shí)間內(nèi),tcpcopy和intercept的交互只用了一個(gè)連接。當(dāng)測(cè)試壓力比較大的時(shí)候,網(wǎng)絡(luò)會(huì)惡化,很容易出現(xiàn)丟包或者來不及接收數(shù)據(jù)的狀況,從而導(dǎo)致大量信息被阻塞住。
后來為了解決單個(gè)連接導(dǎo)致HOL的問題,采用了多個(gè)連接,性能得到了極大提升。
4. Java netty游戲框架
下圖展示了一個(gè)Java netty框架。

一個(gè)線程既用來處理讀數(shù)據(jù),又用來寫數(shù)據(jù),線程一會(huì)兒忙于處理讀事件,一會(huì)兒處理寫事件。集中處理讀事件的時(shí)候,待寫的數(shù)據(jù)被阻塞了,而集中處理寫事件的時(shí)候,讀事件被阻塞了。壓力一大,延遲就會(huì)變得很大。
三、HOL blocking帶來的問題

四、總結(jié)
程序架構(gòu)中,盡量采用多個(gè)連接的方式來處理各種事件,否則很容易遇到TCP的HOL阻塞問題。




























