這篇文章主要介紹了Nginx中HTTP的keepalive相關配置,以及Nginx的Httpd守護程序相關的keepalive timeout配置,需要的朋友可以參考下
http keepalive
在http早期 ,每個http請求都要求打開一個tpc socket連接配接,并且使用一次之後就斷開這個tcp連接配接。使用keep-alive可以改善這種狀态,即在一次TCP連接配接中可以持續發送多份資料而不會 斷開連接配接。通過使用keep-alive機制,可以減少tcp連接配接建立次數,也意味着可以減少TIME_WAIT狀态連接配接,以此提高性能和提高httpd 伺服器的吞吐率(更少的tcp連接配接意味着更少的系統核心調用,socket的accept()和close()調用)。但是,keep-alive并不是 免費的午餐,長時間的tcp連接配接容易導緻系統資源無效占用。配置不當的keep-alive,有時比重複利用連接配接帶來的損失還更大。是以,正确地設定 keep-alive timeout時間非常重要。
keepalvie timeout
Httpd守護程序,一般都提供了keep-alive timeout時間設定參數。比如nginx的keepalive_timeout,和Apache的KeepAliveTimeout。這個 keepalive_timout時間值意味着:一個http産生的tcp連接配接在傳送完最後一個響應後,還需要hold住 keepalive_timeout秒後,才開始關閉這個連接配接。當httpd守護程序發送完一個響應後,理應馬上主動關閉相應的tcp連接配接,設定 keepalive_timeout後,httpd守護程序會想說:”再等等吧,看看浏覽器還有沒有請求過來”,這一等,便是 keepalive_timeout時間。如果守護程序在這個等待的時間裡,一直沒有收到浏覽發過來http請求,則關閉這個http連接配接。
我寫了一個腳本,友善測試
<a href="http://www.jb51.net/article/77595.htm#" target="_blank">?</a>
<code><?php</code>
<code>sleep(60);</code><code>//為了便于分析測試,會根據測試進行調整</code>
<code>echo</code> <code>"www.jb51.net"</code><code>;</code>
<code>?></code>
1.當keepalive_timeout時間為0時,即不啟用Keep-Alive時,一個tcp連接配接的生命周期
<code>#tcpdump -n host 218.1.57.236 and port 80</code>
<code>20:36:50.792731 IP 218.1.57.236.43052 > 222.73.211.215.http: S 1520902589:1520902589(0) win 65535</code>
<code>20:36:50.792798 IP 222.73.211.215.http > 218.1.57.236.43052: S 290378256:290378256(0) ack 1520902590 win 5840</code>
<code>20:36:50.801629 IP 218.1.57.236.43052 > 222.73.211.215.http: . ack 1 win 3276820:36:50.801838 IP 218.1.57.236.43052 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768</code>
<code>20:36:50.801843 IP 222.73.211.215.http > 218.1.57.236.43052: . ack 797 win 5920:37:50.803230 IP 222.73.211.215.http > 218.1.57.236.43052: P 1:287(286) ack 797 win 59</code>
<code>20:37:50.803289 IP 222.73.211.215.http > 218.1.57.236.43052: F 287:287(0) ack 797 win 59</code>
<code>20:37:50.893396 IP 218.1.57.236.43052 > 222.73.211.215.http: . ack 288 win 32625</code>
<code>20:37:50.894249 IP 218.1.57.236.43052 > 222.73.211.215.http: F 797:797(0) ack 288 win 32625</code>
<code>20:37:50.894252 IP 222.73.211.215.http > 218.1.57.236.43052: . ack 798 win 59</code>
第1~3行建立tcp三次握手,建立連接配接。用時8898μs
第4~5行通過建立的連接配接發送第一個http請求,服務端确認收到請求。用時5μs
第5~6行,可以知道腳本執行用時60s1387μs,與php腳本相符。
第6、8行服務端發送http響應。發送響應用時90166μs。
第7行,表明由服務端守護程序主動關閉連接配接。結合第6、8行,說明http響應一旦發送完畢,服務端馬上關閉這個tcp連接配接
第7、9、10說明tcp連接配接順序關閉,用時90963μs。需要注意,這裡socket資源并沒有立即釋放,需要等待2MSL時間(60s)後才被真正釋放。
由此可見,在沒有設定 keepalive_timeout情況下,一個socket資源從建立到真正釋放需要經過的時間是:建立tcp連接配接 + 傳送http請求 + php腳本執行 + 傳送http響應 + 關閉tcp連接配接 + 2MSL 。(注:這裡的時間隻能做參考,具體的時間主要由網絡帶寬,和響應大小而定)
2.當keepalive_timeout時間大于0時,即啟用Keep-Alive時,一個tcp連接配接的生命周期。為了便于分析,我們将keepalive_timeout設定為300s
<code>21:38:05.471129 IP 218.1.57.236.54049 > 222.73.211.215.http: S 1669618600:1669618600(0) win 65535</code>
<code>21:38:05.471140 IP 222.73.211.215.http > 218.1.57.236.54049: S 4166993862:4166993862(0) ack 1669618601 win 5840</code>
<code>21:38:05.481731 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 1 win 32768</code>
<code>21:38:05.481976 IP 218.1.57.236.54049 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768</code>
<code>21:38:05.481985 IP 222.73.211.215.http > 218.1.57.236.54049: . ack 797 win 59</code>
<code>21:38:07.483626 IP 222.73.211.215.http > 218.1.57.236.54049: P 1:326(325) ack 797 win 59</code>
<code>21:38:07.747614 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 326 win 32605</code>
<code>21:43:07.448454 IP 222.73.211.215.http > 218.1.57.236.54049: F 326:326(0) ack 797 win 59</code>
<code>21:43:07.560316 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 327 win 32605</code>
<code>21:43:11.759102 IP 218.1.57.236.54049 > 222.73.211.215.http: F 797:797(0) ack 327 win 32605</code>
<code>21:43:11.759111 IP 222.73.211.215.http > 218.1.57.236.54049: . ack 798 win 59</code>
我們先看一下,第6~8行,跟上次示例不一樣的是,服務端httpd守護程序發完響應後,沒有立即主動關閉tcp連接配接。
第8行,結合第6行,我們可以看到,5分鐘(300s)後,服務端主動關閉這個tcp連接配接。這個時間,正是我們設定的keepalive_timeout的時間。
由此可見,設定了keepalive_timout時間情況下,一個socket建立到釋放需要的時間是多了keepalive_timeout時間。
3.當keepalive_timeout時間大于0,并且在同一個tcp連接配接發送多個http響應。這裡為了便于分析,我們将keepalive_timeout設定為180s
通過這個測試,我們想弄清楚,keepalive_timeout是從第一個響應結束開啟計時,還是最後一個響應結束開啟計時。測試結果證明是後者,這裡,我們每隔120s發一次請求,通過一個tcp連接配接發送了3個請求。
<code># tcpdump -n host 218.1.57.236 and port 80</code>
<code>22:43:57.102448 IP 218.1.57.236.49955 > 222.73.211.215.http: S 4009392741:4009392741(0) win 65535</code>
<code>22:43:57.102527 IP 222.73.211.215.http > 218.1.57.236.49955: S 4036426778:4036426778(0) ack 4009392742 win 5840</code>
<code>22:43:57.111337 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1 win 3276822:43:57.111522 IP 218.1.57.236.49955 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768</code>
<code>22:43:57.111530 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 797 win 59</code>
<code>22:43:59.114663 IP 222.73.211.215.http > 218.1.57.236.49955: P 1:326(325) ack 797 win 59</code>
<code>22:43:59.350143 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 326 win 3260522:45:59.226102 IP 218.1.57.236.49955 > 222.73.211.215.http: P 1593:2389(796) ack 650 win 32443</code>
<code>22:45:59.226109 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 2389 win 83</code>
<code>22:46:01.227187 IP 222.73.211.215.http > 218.1.57.236.49955: P 650:974(324) ack 2389 win 83</code>
<code>22:46:01.450364 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 974 win 3228122:47:57.377707 IP 218.1.57.236.49955 > 222.73.211.215.http: P 3185:3981(796) ack 1298 win 32119</code>
<code>22:47:57.377714 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 3981 win 108</code>
<code>22:47:59.379496 IP 222.73.211.215.http > 218.1.57.236.49955: P 1298:1622(324) ack 3981 win 108</code>
<code>22:47:59.628964 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1622 win 3276822:50:59.358537 IP 222.73.211.215.http > 218.1.57.236.49955: F 1622:1622(0) ack 3981 win 108</code>
<code>22:50:59.367911 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1623 win 32768</code>
<code>22:50:59.686527 IP 218.1.57.236.49955 > 222.73.211.215.http: F 3981:3981(0) ack 1623 win 32768</code>
<code>22:50:59.686531 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 3982 win 108</code>
第一組,三個ip包表示tcp三次握手建立連接配接,由浏覽器建立。
第二組,發送第一次http請求并且得到響應,服務端守護程序輸出響應之後,并沒馬上主動關閉tcp連接配接。而是啟動keepalive_timout計時。
第三組,2分鐘後,發送第二次http請求并且得到響應,同樣服務端守護程序也沒有馬上主動關閉tcp連接配接,重新啟動keepalive_timout計時。
第四組,又2分鐘後,發送了第三次http請求并且得到響應。伺服器守護程序依然沒有主動關地閉tcp連接配接(距第一次http響應有4分鐘了,大于keepalive_timeout值),而是重新啟動了keepalive_timout計時。
第五組,跟最後一個響應keepalive_timeout(180s)内,守護程序再沒有收到請求。計時結束,服務端守護程序主動關閉連接配接。4次揮手後,服務端進入TIME_WAIT狀态。
這說明,當設定了keepalive_timeout,一個socket由建立到釋放,需要時間是:tcp建立 + (最後一個響應時間 – 第一個請求時間) + tcp關閉 + 2MSL。紅色加粗表示每一次請求發送時間、每一次請求腳本執行時間、每一次響應發送時間,還有兩兩請求相隔時間。進一步測試,正在關閉或者 TIME_WAIT狀态的tcp連接配接,不能傳輸http請求和響應。即,當一個連接配接結束keepalive_timeout計時,服務端守護程序發送第一 個FIN标志ip包後,該連接配接不能再使用了。
http keep-alive與tcp keep-alive
http keep-alive與tcp keep-alive,不是同一回事,意圖不一樣。http keep-alive是為了讓tcp活得更久一點,以便在同一個連接配接上傳送多個http,提高socket的效率。而tcp keep-alive是TCP的一種檢測TCP連接配接狀況的保鮮機制。tcp keep-alive保鮮定時器,支援三個系統核心配置參數:
<code>echo 1800 > /proc/sys/net/ipv4/tcp_keepalive_time</code>
<code>echo 15 > /proc/sys/net/ipv4/tcp_keepalive_intvl</code>
<code>echo 5 > /proc/sys/net/ipv4/tcp_keepalive_probes</code>
keepalive是TCP保鮮定時器,當網絡兩端建立了TCP連接配接之後,閑置idle(雙方沒有任何資料流發送往來)了 tcp_keepalive_time後,伺服器核心就會嘗試向用戶端發 送偵測包,來判斷TCP連接配接狀況(有可能用戶端崩潰、強制關閉了應用、主機不可達等等)。如果沒有收到對方的回答(ack包),則會在 tcp_keepalive_intvl後再次嘗試發送偵測包,直到收到對對方的ack,如果一直沒有收到對方的ack,一共會嘗試 tcp_keepalive_probes次,每次的間隔時間在這裡分别是15s, 30s, 45s, 60s, 75s。如果嘗試tcp_keepalive_probes,依然沒有收到對方的ack包,則會丢棄該TCP連接配接。TCP連接配接預設閑置時間是2小時,一般 設定為30分鐘足夠了。也就是說,僅當nginx的keepalive_timeout值設定高于tcp_keepalive_time,并且距此tcp連接配接傳輸的最後一 個http響應,經過了tcp_keepalive_time時間之後,作業系統才會發送偵測包來決定是否要丢棄這個TCP連接配接。一般不會出現這種情況, 除非你需要這樣做。
keep-alive與TIME_WAIT
使用http keep-alvie,可以減少服務端TIME_WAIT數量(因為由服務端httpd守護程序主動關閉連接配接)。道理很簡單,相較而言,啟用keep-alive,建立的tcp連接配接更少了,自然要被關閉的tcp連接配接也相應更少了。
最後
我想用一張示意圖檔來說明使用啟用keepalive的不同。另外,http keepalive是用戶端浏覽器與服務端httpd守護程序協作的結果,是以,我們另外安排篇幅介紹不同浏覽器的各種情況對keepalive的利用。
<a href="http://files.jb51.net/file_images/article/201601/201616153500660.png?201606153518" target="_blank"></a>
本文轉自 憬薇 51CTO部落格,原文連結:http://blog.51cto.com/welcomeweb/1931087