http, keepalive用來複用連接,這樣不就是串列的了么,瀏覽器會並行的多個請求發出,keepalive怎麼體現作用?

如題,瀏覽器並行的發出請求不行的么?既然並行發出請求,那麼keepalive作用怎麼體現。


首先並行是靠多連接的,不過HTTP協議規定單個客戶端對相同域名的並發連接是受限的,以前是兩個,所以誕生了把資源放在不同域名下的優化技術。

那就假設一個連接好了,同時發起10個請求,則必須一個個處理,沒有KeepAlive的話,每個請求結束後都會關閉TCP連接,下一個請求需要重新連接。有KeepAlive後連接不關閉,下個請求復用該連接。


時間開銷分為兩部分,一部分和帶寬成反比,一部分和延時成正比。很多人想當然地以為帶寬一定是瓶頸,那是因為你只有在等待下載大文件時才對時間開銷有感覺,而這時候瓶頸必然是帶寬。但實際上必須做過 profiling 你才知道你手頭上的問題瓶頸在帶寬還是延時。具體問題具體分析。

如果你用 Chrome 的來分析 network 的話,你就會發現小文件如 JS/CSS 瓶頸其實在延時。假設你有個 JS 大小是 100KB,然後你在用 2Mbps 的 ADSL,帶寬耗時是 400ms。在開始傳輸這 100KB 前,DNS 查詢要 1 個 RTT(往返時間,即 ping 時間),建立 TCP 連接要 1 個 RTT,再建立 SSL 要 3 個 RTT,之後 HTTP 發請求又 1 個 RTT。假設你的 ping 是 25ms,6 個 RTT 就是 150ms。總和 550ms,延時佔總和的 27%。這絕對不是個小數字,能優化掉必須優化掉。

DNS 緩存、持久連接(keep alive)、SPDY server push/hint 分別用於解決上述幾個 RTT。此外上面說的還只是 ADSL,如果你用 4G RTT 會上到 100ms,3G 能超過 200ms。實際網站也很少給你單個 100KB 的 JS,往往是分開多個更小的 JS。這時候優化延時就顯得很重要。

P.S. 性能問題不是背一下 HTTP 標準就能解決的,你必須做過 profiling 才知道瓶頸在哪裡。在非瓶頸外優化是沒有意義的,優化帶來的開銷可能還加重了瓶頸。


keepalive之前,是發出一個request,然後等待收取 response,在沒有 conten-length的時候利用關閉鏈接的事件來判斷 response接收完畢。因為那個時候網站就是一個HTML的文本,你僅僅需要請求一次就可以得到整個頁面了。

後來,隨著網頁表現形式的多樣化,一個頁面的資源增多,構成一個頁面的文件數不再是一個,為了快速載入網頁(是快速,理論上你只開一個socket用完了關,再用再開也行),同時並行地打開多個socket來獲取資源(網路IO時間和頁面渲染時間的比重越大,這個效果越明顯)。

這個時候有一個問題就來了,我們為什麼不在 一個socket上連續發送多個request。原因是因為HTTP1.1 及更低版本的協議,並沒有一個欄位用來區分一個response是歸屬於哪一個request的。但HTTP 2 就有這個欄位了。因此在HTTP1.1 及更低版本,你只能在發送一個request之後,等待response的到來。

直到今日,應用最廣泛的依然是HTTP1.1 協議,這就造成了目前瀏覽器都是並行載入的,是的都是並行的。

在真正試圖解決你的疑問的之前,我們來看一下,從發出request之前到接收respon之後,都發生了什麼。

0.你向瀏覽器的地址欄輸入一個域名.如 http://www.zhihu.com

1.瀏覽器向你的本地DNS伺服器請求解析該域名,即將你的http://www.zhihu.com 解析為真實的IP地址.詳細協議請查詢RFC文檔,其中對DNS協議的格式內容,指令意義,壓縮演算法,等都作出了規定。

2.拿到ip地址之後,發起TCP 握手(3次),詳情請看計算機網路TCP協議部分

3.握手成功,構造request,即 HTTP 中request請求.並發送到目的地。有關HTTP協議的內容請查閱RFC文檔可以購買HTTP權威指南作為參考和釋疑.

4.伺服器接受到一個完整的request(該邊界的指定一般是conten-length,chunked也有),根據用戶的request內容運算出相應的response。

5.伺服器將response 沿著request建立的連接,向瀏覽器(客戶端)發送數據。

5.5 keepalive的時候不關閉該連接,沒有keepalive的時候發起tcp close,4次握手

6.瀏覽器根據接收到的response開始渲染頁面。

至此,一個網頁的打開過程完畢,我們從中提取出耗時的部分。

1.DNS查詢時間(一來一回,走UDP協議) 網路IO

2.tcp 建立連接握手 網路IO

3.request構造時間(cpu運算)

4.request發送完畢時間(網路IO)

5.伺服器接收request運算構造response(CPU運算,特指構造response過程中沒有任何IO操作)

6.伺服器發送response到客戶端的時間(網路IO)

6.5 伺服器關閉連接時間(IO)

7.客戶端接收數據渲染頁面時間(cpu運算)。

至此,一個流程就這樣簡單地構造完畢了。

好了,我們的目標是,儘可能地縮短完成一個頁面載入的時間。

那麼我們就需要不斷地削減上述時間中的某一個。

到底什麼才是最好的方案,將隨著上述時間的比重不斷地變化,沒有什麼是最優的。

瀏覽器默認的常用做法是,並行打開多個連接向伺服器請求資源.

(這裡要注意)請求第一個頁面的時候,只有一個連接(有的瀏覽器為了加速後面的多tcp問題,會有預連接,但是效果卻因為資源不一定在一個ip上或者伺服器不支持過多的連接而沒有太大效果),這裡請求道的response之後解析出其關聯的其他資源,才開始並行連接獲取資源。

但是,tcp的握手和關閉是一個想當耗時,而且重複的過程(當傳輸速度變快的時候這個的比重相當大),因此 keepalive的作用就是用來 復用已經打開的tcp連接.

這裡有個數學問題,請求6個資源是,開3個連接復用三個呢,還是開6個連接,這就看情況了。

綜上回答題主的問題:

1.瀏覽器已經並行了,這個跟你想的不一樣.

2.keepalive,是復用的意思,不是連續發出多個request.(這是HTTP1.1),不算是串列。

個人看法:

HTTP1.1 request和response 的無標識符問題(即response無法指明是哪一個request的),就造就了現在這種情況。HTTP 2 協議解除了這個問題。

HTTP 1.1,也沒有一個request 多個 response的機制,沒request,光有response的機制。關於這個特性HTTP 2有實現,但是爭議依然比較大。

廢話那麼多,希望能幫到你,如有錯誤疏漏,歡迎指正。


HTTP/1.1的KeepAlive就是串列的會話模式,一去一回,省掉的是TCP層面重複創建的成本

HTTP/2支持多路復用,就是你說的並行模式


keeplive:

tcp open---&>request1---&>response1---&>request2---&>response2...---&>tcp close

並行:

tcp open---&>request1---&>response1---&>tcp close

同時

tcp open---&>request2---&>response2---&>tcp close

...

tcp open---&>requestN---&>responseN---&>tcp close

pipeline:

tcp open---&>request1---&>request2...---&>requestN---&>response1---&>response2...---&>responseN---&>tcp close

http 0.9和http 1.0時代:

tcp open---&>request1---&>response1---&>tcp close完成後

tcp open---&>request2---&>response2---&>tcp close


Keepalive 目的是在過期時間內保持瀏覽器端與伺服器端間的連接,並行與串列不是Keep alive關注的點。


瀏覽器的實現都是既有並發多連接,並且每個連接keepalive


keep-alive是什麼?

keep-alive是實現「持久連接」的一種方式(另外一種方式是HTTP/1.1 「persistent」連接,很少用)。「持久連接」,大意為在一個請求完成之後,暫不關閉連接,給後面的請求復用。HTTP1.1(已經HTTP/1.0的各種增強版本)允許HTTP設備在事務處理結束後將TCP連接保持在打開狀態,以便為未來的HTTP請求重用現存的連接。持久連接會在不同事務之間保持打開狀態,直到客戶端或伺服器端決定將其關閉為止。

現代瀏覽器就是並行連接的。

現在的瀏覽器基本上都會在適合的適合併行載入資源的。打開你的chrome,隨便找個網站看看它的網路請求,從時間軸可以看到有些請求時並行的。每個瀏覽器的並行連接數量是有限的。

(2011年5月24日數據,來源:各瀏覽器的並行連接數(同域名))

keep-alive和並行連接沒有直接的關係。

一個是說連接保持長時間後才關閉,一個是說同時發多條連接,互不影響的。

上述部分資料搬運自《HTTP權威指南》,那是一本好書,建議去讀讀。


只是減少了建立TCP連接的時間,用pipeline可以大幅加速 req req req --&> &<--- resp resp resp


連接的速度是很快的,瓶頸主要是在創建連接上,串列就夠快的了。


1. HTTP是一種半雙工的協議,也就是說,雖然建立的連接可以讀寫,但是同一時間,只能讀,或者只能寫,當然PIPELINE除外。如果只用一個連接,意味著頁面每個資源都要串列傳輸,效率自然比較低。

2. HTTP之下是TCP,連接建立需要經過一次握手過程,也就是一次round trip,KEEP-ALIVE可以復用已經建立的連接,減少連接建立的開銷。


減少建立連接的開銷。


推薦閱讀:

NoHttp 與 OKHttp 異同?以及兩者的發展前景?
如何理解華為公有雲中提到的全動態BGP?
小米路由器是外包做的嗎?
網路尖兵如何檢查同一IP地址的數據包中是否有不同的MAC地址?

TAG:萬維網聯盟W3C | 計算機網路 | HTTP |