關於HTTP中的keep-alive

一. 關於HTTP

    首先,HTTP是超文本傳輸協議,是一個基於請求與響應模式的、無狀態的、應用層的協議,常基於TCP的連接方式,其主要特點有如下:

  1. 支持客戶/服務器模式;

  2. 簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。每種方法規定了客戶與服務器聯繫的類型不同。由於HTTP協議簡單,使得HTTP服務器的程序規模小,因而通信速度很快;

  3. 靈活:HTTP允許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type加以標記;

  4. 無連接:無連接的含義是限制每次連接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答後,即斷開連接。採用這種方式可以節省傳輸時間;

  5. 無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味着如果後續處理需要前面的信息,則它必須重傳,這樣可能導致每次連接傳送的數據量增大。另一方面,在服務器不需要先前信息時它的應答就較快。



二. keep-alive

    既然上面提到了HTTP是基於請求與響應的,且最主要的兩個特點就是無連接和無狀態,但需要說明的是,雖然是無連接的,但其底層也就是傳輸層大多卻是基於 TCP面向連接的通信方式,因此,這裏的無連接指的是:當server端和client端進行通訊的時候,client端向server端發起請 求,server端接收請求之後返回給client端一個響應,之後就會斷開不再繼續保持連接了;這樣有一個好處就是對於只有一次訪問的連接來說不僅節省 資源還很高效,但很明顯,如果client端還想繼續多次訪問server端就需要重新建立連接也就是會多次進行TCP的“三次握手,四次揮手”的過程, 這樣一來並沒有節省資源而且還很低效,因此,使用keep-alive(又稱持久連接、連接重用)可以改善這種狀態,即在一次TCP連接中可以持續發送多份數據而不會斷開連接。通過使用keep-alive機制,避免了建立或者重新建立連接的次數,也意味着可以減少TIME_WAIT狀態連接,以此提高性能和提高httpd服務器的吞吐率(更少的TCP連接意味着更少的系統內核調用,socket的accept()和close()調用)。


    HTTP 1.0 中keep-alive默認是關閉的,需要在HTTP頭加入"Connection: Keep-Alive",才能啓用Keep-Alive;HTTP 1.1中默認啓用Keep-Alive,如果加入"Connection: close ",才關閉。目前大部分瀏覽器都是用HTTP 1.1協議,也就是說默認都會發起Keep-Alive的連接請求了,所以是否能完成一個完整的Keep- Alive連接就看服務器設置情況。

    其中,RFC 2616 (P47)指出:單用戶客戶端與任何服務器或代理之間的連接數不應該超過2個。一個代理與其它服務器或代碼之間應該使用不超過2 * N的活躍併發連接。這是爲了提高HTTP響應時間,避免擁塞(冗餘的連接並不能代碼執行性能的提升)。



三. keep-alive timeout時間

    keep-alive並不是免費的午餐,長時間的TCP連接容易導致系統資源無效佔用,配置不當的keep-alive 有時比重複利用連接帶來的損失還更大;因此,正確地設置keep-alive timeout時間非常重要。

    httpd守護進程一般都提供了keep-alive timeout時間設置參數,比如nginx的keepalive_timeout和Apache的keepalivetimeout。這個 keepalive_timeout時間值意味着:一個http產生的TCP連接在傳送完最後一個響應後,還需要保持keepalive_timeout 時間後纔開始關閉這個連接;

    

    在沒有設置keepalive_timeout的情況下,一個socket資源從建立到真正釋放所需要經過的時間是:建立TCP連接(三次握手)+傳送http請求+腳本指向+傳送http響應+關閉TCP連接(四次揮手)+主動關閉的一方進入TIME_WAIT的2MSL等待時間

    當設定了keepalive_timeout時間之後,一個socket由建立到釋放所需要經過的時間是:TCP建立連接(三次握手)+(最後一次響應 - 第一次請求時間)+TCP關閉連接(四次揮手)+2MSL; 也就是說,當使用keep-alive機制的時候,當一次請求-響應結束之後,這個連接還會繼續維持上keepalive_timeout時間,如果在這 個時間內client端還有請求發過來,那麼server端會繼續處理給予響應,如果keepalive_timeout時間計時結束後,就會進入TCP 釋放連接的階段,因此也就會結束掉這次通信;



四. keep-alive模式的使用

    雖然keep-alive模式可以降低TCP連接的次數提高效率,但並不是什麼情況下都適合使用keep-alive機制的,如下舉個栗子:

    比如很多網頁中圖片、CSS、JS、Html都在一臺Server上,當用戶訪問其中的Html網頁時,網頁中的圖片、Css、Js都構成了訪問請求,打開KeepAlive屬性可以有效地降低TCP握手的次數(當然瀏覽器對同一域下同時請求的圖片數有限制,一般是2),減少httpd進程數,從而降低內存的使用(假定prefork模式)。MaxKeepAliveRequestsKeepAliveTimeOut兩個屬性在KeepAlive=On時起作用,可以控制持久連接的生存時間和最大服務請求數。 

             不過,上面說的只是一種情形,那就是靜態網頁居多的情況下,並且網頁中的其他請求與網頁在同一臺Server上。當你的應用動態程序(比如:php)居多,用戶訪問時由動態程序即時生成html內容,html內容中圖片素材和Css、Js等比較少或者散列在其他Server上時,KeepAlive=On反而會降低Apache的性能。爲什麼呢?

             前面提到過,KeepAlive=On時,每次用戶訪問,打開一個TCP連接,Apache都會保持該連接一段時間,以便該連接能連續爲同一client服務,在KeepAliveTimeOut還沒到期並且MaxKeepAliveRequests還沒到閾值之前,Apache必然要有一個httpd進程來維持該連接,httpd進程不是廉價的,他要消耗內存和CPU時間片的。假如當前Apache每秒響應100個用戶訪問,KeepAliveTimeOut=5,此時httpd進程數就是100*5=500個(prefork模式),一個httpd進程消耗5M內存的話,就是500*5M=2500M=2.5G,誇張吧?當然,Apache與Client只進行了100次TCP連接。如果你的內存夠大,系統負載不會太高,如果你的內存小於2.5G,就會用到Swap,頻繁的Swap切換會加重CPU的Load。
             現在我們關掉KeepAliveApache仍然每秒響應100個用戶訪問,因爲我們將圖片、js、css等分離出去了,每次訪問只有1個request,此時httpd的進程數是100*1=100個,使用內存100*5M=500M,此時Apache與Client也是進行了100次TCP連接。性能卻提升了太多。

因此,總結:

  1. 當你的Server內存充足時,KeepAlive=On還是Off對系統性能影響不大;

  2. 當你的Server上靜態網頁(Html、圖片、Css、Js)居多時,建議打開KeepAlive;

  3. 當你的Server多爲動態請求(因爲連接數據庫,對文件系統訪問較多),KeepAlive關掉,會節省一定的內存,節省的內存正好可以作爲文件系統的Cache(vmstat命令中cache一列),降低I/O壓力;

PS:當KeepAlive=On時,KeepAliveTimeOut的設置其實也是一個問題,設置的過短,會導致Apache頻繁建立連接,給Cpu造成壓力,設置的過長,系統中就會堆積無用的Http連接,消耗掉大量內存,具體設置多少,可以進行不斷的調節,因你的網站瀏覽和服務器配置而異。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章