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