當(dāng)前,幾乎所有互聯(lián)網(wǎng)上的內(nèi)容都采用HTTP 1.1作為通信協(xié)議。人們?cè)谠搮f(xié)議上投入了大量精力,因此基于該協(xié)議的基礎(chǔ)架構(gòu)得以日臻完善。得益于此,在現(xiàn)有的HTTP協(xié)議之上構(gòu)建新的方案會(huì)比從底層建立新的協(xié)議要容易得多。
HTTP剛誕生的時(shí)候被看作一個(gè)相對(duì)簡(jiǎn)單直觀的協(xié)議,但時(shí)間證明了早期的設(shè)計(jì)并不盡人意。于1996年發(fā)布的、描述HTTP 1.0規(guī)范的RFC 1945只有60頁,但僅僅3年之后,描述HTTP 1.1規(guī)范的RFC 2616就驟增至176頁。當(dāng)我們?cè)贗ETF小組對(duì)該規(guī)范進(jìn)行更新時(shí),更是被拆分成了總頁數(shù)更多的六個(gè)文檔(這就是RFC 7230及其文件族的由來與誕生)。總而言之,HTTP 1.1包含了太多細(xì)節(jié)和可選內(nèi)容,這讓它變得過于龐大。
HTTP 1.1不僅包含了非常多的細(xì)枝末節(jié),也為未來的擴(kuò)展預(yù)留了很多選項(xiàng)。這種事無巨細(xì)的風(fēng)格導(dǎo)致在現(xiàn)有的軟件生態(tài)中,幾乎沒有任何實(shí)際場(chǎng)景真正實(shí)現(xiàn)了協(xié)議中提及的所有細(xì)節(jié),甚至要弄清楚“所有細(xì)節(jié)”到底包括哪些內(nèi)容都非常困難。這也導(dǎo)致了很多最初不常用的功能在后來的實(shí)現(xiàn)中得到很少支持,而有些最初實(shí)現(xiàn)了的功能,卻又很少被使用。
隨著時(shí)間推移,當(dāng)客戶端和服務(wù)器開始增加對(duì)于這些功能的使用時(shí),互用性(interoperability)問題就暴露了出來。HTTP管線化(HTTP Pipelining)就是一個(gè)非常好的例子。
HTTP 1.1很難完全使用出TCP協(xié)議能提供的所有強(qiáng)大能力。HTTP客戶端和瀏覽器必須要另辟蹊徑,去尋找新的解決方案來降低頁面載入時(shí)間。
與此同時(shí),人們也嘗試使用新的協(xié)議來替代TCP,但結(jié)果證明這也非常困難。無奈之下,我們只能嘗試同時(shí)改進(jìn)TCP協(xié)議本身和基于TCP的上層協(xié)議。
簡(jiǎn)單來說,我們可以通過更好的利用TCP來減少傳輸過程中的中斷,并充分挖掘利用那些本可以用于發(fā)送/接受更多數(shù)據(jù)的時(shí)間。下面幾段我們將會(huì)著重討論這些問題。
如果仔細(xì)觀察那些最流行的網(wǎng)站首頁所需要下載的資源,會(huì)發(fā)現(xiàn)一個(gè)非常明顯的趨勢(shì)。近年來加載網(wǎng)站首頁接受的數(shù)據(jù)量在逐漸增加,并已經(jīng)超過了1.9MB。但更重要的是:平均每個(gè)頁面為了完成渲染需要加載超過100個(gè)獨(dú)立資源。
正如下圖所示,這種趨勢(shì)已經(jīng)持續(xù)了很長一段時(shí)間,并且沒有減緩的跡象。該圖表中綠色直線展示了傳輸數(shù)據(jù)大小的增長,紅色直線展示了平均請(qǐng)求資源數(shù)量的增長。
HTTP 1.1對(duì)網(wǎng)絡(luò)延遲非常敏感。部分原因是HTTP Pipelining還存有很多問題,所以對(duì)大部分用戶來說這項(xiàng)技術(shù)是被默認(rèn)關(guān)閉的。
雖然近幾年來網(wǎng)絡(luò)帶寬增長非???,然而我們卻并沒有看到網(wǎng)絡(luò)延遲有對(duì)應(yīng)程度的降低。在高延遲的網(wǎng)絡(luò)環(huán)境中(比如移動(dòng)設(shè)備),即使擁有高連接速率,也很難獲得優(yōu)質(zhì)快速的網(wǎng)絡(luò)體驗(yàn)。
另外一個(gè)需要低延遲的場(chǎng)景是某些視頻服務(wù),如視頻會(huì)議、游戲和其它類似無法預(yù)先發(fā)送資源請(qǐng)求的情況。
HTTP Pipelining是這樣一種技術(shù):在等待上一個(gè)請(qǐng)求響應(yīng)的同時(shí),發(fā)送下一個(gè)請(qǐng)求。(譯者注:作者這個(gè)解釋并不完全正確,HTTP Pipelining其實(shí)是把多個(gè)HTTP請(qǐng)求放到一個(gè)TCP連接中一一發(fā)送,而在發(fā)送過程中不需要等待服務(wù)器對(duì)前一個(gè)請(qǐng)求的響應(yīng);只不過,客戶端還是要按照發(fā)送請(qǐng)求的順序來接收響應(yīng)。)但就像在超市收銀臺(tái)或者銀行柜臺(tái)排隊(duì)時(shí)一樣,你并不知道前面的顧客是干脆利索的還是會(huì)跟收銀員/柜員磨蹭到世界末日(譯者注:不管怎么說,服務(wù)器(即收銀員/柜員)是要按照順序處理請(qǐng)求的,如果前一個(gè)請(qǐng)求非常耗時(shí)(顧客磨蹭),那么后續(xù)請(qǐng)求都會(huì)受到影響),這就是所謂的線頭阻塞(Head of line blocking)。
當(dāng)然,你可以在選擇隊(duì)伍時(shí)就做足準(zhǔn)備,去排一個(gè)你認(rèn)為最快的隊(duì)伍,或者甚至另起一個(gè)新的隊(duì)伍(譯者注:即新建一個(gè)TCP連接)。但不管怎么樣,你總歸得先選擇一個(gè)隊(duì)伍,而且一旦選定之后,就不能更換隊(duì)伍。
但是,另起新隊(duì)伍會(huì)導(dǎo)致資源耗費(fèi)和性能損失(譯者注:新建 TCP 連接的開銷非常大)。這種另起新隊(duì)伍的方式只在新隊(duì)伍數(shù)量很少的情況下有作用,因此它并不具備可擴(kuò)展性。(譯者注:這段話意思是說,靠大量新建連接是不能有效解決延遲問題的,即HTTP Pipelining并不能徹底解決Head of line blocking問題。)所以針對(duì)此問題并沒有完美的解決方案。
這就是為什么,即使在2015年的今天,大部分桌面瀏覽器仍然會(huì)選擇默認(rèn)關(guān)閉HTTP pipelining這一功能的原因。
關(guān)于這個(gè)問題的更多細(xì)節(jié),可以參閱Firefox的 bugzilla #264354。
更多建議: