在經過調試工具查看網絡請求的時候,一般在response header能看到相似下面這種:Keep-Alive: timeout=10, max=94 。那麼Keep-Alive究竟是什麼呢?php
在http早期,每一個http請求都要求打開一個tpc socket鏈接,而且使用一次以後就斷開這個tcp鏈接。nginx
使用keep-alive能夠改善這種狀態,即在一次TCP鏈接中能夠持續發送多份數據而不會斷開鏈接。經過使用keep-alive機制,能夠減小tcp鏈接創建次數,也意味着能夠減小TIME_WAIT狀態鏈接,以此提升性能和提升httpd服務器的吞吐率(更少的tcp鏈接意味着更少的系統內核調用,socket的accept()和close()調用)。瀏覽器
可是,keep-alive並非免費的午飯,長時間的tcp鏈接容易致使系統資源無效佔用。配置不當的keep-alive,有時比重複利用鏈接帶來的損失還更大。因此,正確地設置keep-alive 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鏈接。socket
下面寫一個腳本,方便測試:tcp
1 sleep(60); //爲了便於分析測試,會根據測試進行調整 2 echo "www.example.com";
1. 當keepalive_timeout時間爲0時,即不啓用Keep-Alive時,一個tcp鏈接的生命週期:工具
01 #tcpdump -n host 218.1.57.236 and port 80 02 20:36:50.792731 IP 218.1.57.236.43052 > 222.73.211.215.http: S 1520902589:1520902589(0) win 65535 03 20:36:50.792798 IP 222.73.211.215.http > 218.1.57.236.43052: S 290378256:290378256(0) ack 1520902590 win 5840 04 20:36:50.801629 IP 218.1.57.236.43052 > 222.73.211.215.http: . ack 1 win 32768 05 06 20:36:50.801838 IP 218.1.57.236.43052 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768 07 20:36:50.801843 IP 222.73.211.215.http > 218.1.57.236.43052: . ack 797 win 59 08 09 20:37:50.803230 IP 222.73.211.215.http > 218.1.57.236.43052: P 1:287(286) ack 797 win 59 10 20:37:50.803289 IP 222.73.211.215.http > 218.1.57.236.43052: F 287:287(0) ack 797 win 59 11 20:37:50.893396 IP 218.1.57.236.43052 > 222.73.211.215.http: . ack 288 win 32625 12 20:37:50.894249 IP 218.1.57.236.43052 > 222.73.211.215.http: F 797:797(0) ack 288 win 32625 13 20:37:50.894252 IP 222.73.211.215.http > 218.1.57.236.43052: . ack 798 win 59
因而可知,在沒有設置 keepalive_timeout 狀況下,一個socket資源從創建到真正釋放須要通過的時間是:創建tcp鏈接 + 傳送http請求 + php腳本執行 + 傳送http響應 + 關閉tcp鏈接 + 2MSL 。(注:這裏的時間只能作參考,具體的時間主要由網絡帶寬,和響應大小而定)性能
2. 當keepalive_timeout時間大於0時,即啓用Keep-Alive時,一個tcp鏈接的生命週期。爲了便於分析,咱們將keepalive_timeout設置爲300s測試
01 #tcpdump -n host 218.1.57.236 and port 80 02 21:38:05.471129 IP 218.1.57.236.54049 > 222.73.211.215.http: S 1669618600:1669618600(0) win 65535 03 21:38:05.471140 IP 222.73.211.215.http > 218.1.57.236.54049: S 4166993862:4166993862(0) ack 1669618601 win 5840 04 21:38:05.481731 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 1 win 32768 05 21:38:05.481976 IP 218.1.57.236.54049 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768 06 21:38:05.481985 IP 222.73.211.215.http > 218.1.57.236.54049: . ack 797 win 59 07 08 21:38:07.483626 IP 222.73.211.215.http > 218.1.57.236.54049: P 1:326(325) ack 797 win 59 09 21:38:07.747614 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 326 win 32605 10 21:43:07.448454 IP 222.73.211.215.http > 218.1.57.236.54049: F 326:326(0) ack 797 win 59 11 21:43:07.560316 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 327 win 32605 12 21:43:11.759102 IP 218.1.57.236.54049 > 222.73.211.215.http: F 797:797(0) ack 327 win 32605 13 21:43:11.759111 IP 222.73.211.215.http > 218.1.57.236.54049: . ack 798 win 59
3. 當keepalive_timeout時間大於0,而且在同一個tcp鏈接發送多個http響應。這裏爲了便於分析,咱們將keepalive_timeout設置爲180s
經過這個測試,咱們想弄清楚,keepalive_timeout是從第一個響應結束開啓計時,仍是最後一個響應結束開啓計時。測試結果證明是後者,這裏,咱們每隔120s發一次請求,經過一個tcp鏈接發送了3個請求。
01 # tcpdump -n host 218.1.57.236 and port 80 02 22:43:57.102448 IP 218.1.57.236.49955 > 222.73.211.215.http: S 4009392741:4009392741(0) win 65535 03 22:43:57.102527 IP 222.73.211.215.http > 218.1.57.236.49955: S 4036426778:4036426778(0) ack 4009392742 win 5840 04 22:43:57.111337 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1 win 32768 05 06 22:43:57.111522 IP 218.1.57.236.49955 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768 07 22:43:57.111530 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 797 win 59 08 22:43:59.114663 IP 222.73.211.215.http > 218.1.57.236.49955: P 1:326(325) ack 797 win 59 09 22:43:59.350143 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 326 win 32605 10 11 22:45:59.226102 IP 218.1.57.236.49955 > 222.73.211.215.http: P 1593:2389(796) ack 650 win 32443 12 22:45:59.226109 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 2389 win 83 13 22:46:01.227187 IP 222.73.211.215.http > 218.1.57.236.49955: P 650:974(324) ack 2389 win 83 14 22:46:01.450364 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 974 win 32281 15 16 22:47:57.377707 IP 218.1.57.236.49955 > 222.73.211.215.http: P 3185:3981(796) ack 1298 win 32119 17 22:47:57.377714 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 3981 win 108 18 22:47:59.379496 IP 222.73.211.215.http > 218.1.57.236.49955: P 1298:1622(324) ack 3981 win 108 19 22:47:59.628964 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1622 win 32768 20 21 22:50:59.358537 IP 222.73.211.215.http > 218.1.57.236.49955: F 1622:1622(0) ack 3981 win 108 22 22:50:59.367911 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1623 win 32768 23 22:50:59.686527 IP 218.1.57.236.49955 > 222.73.211.215.http: F 3981:3981(0) ack 1623 win 32768 24 22:50:59.686531 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 3982 win 108
這說明,當設定了keepalive_timeout,一個socket由創建到釋放,須要時間是:tcp創建 + (最後一個響應時間 – 第一個請求時間) + tcp關閉 + 2MSL。紅色加粗表示每一次請求發送時間、每一次請求腳本執行時間、每一次響應發送時間,還有兩兩請求相隔時間。進一步測試,正在關閉或者TIME_WAIT狀態的tcp鏈接,不能傳輸http請求和響應。即,當一個鏈接結束keepalive_timeout計時,服務端守護進程發送第一個FIN標誌ip包後,該鏈接不能再使用了。
http keep-alive與tcp keep-alive,不是同一回事,意圖不同。http keep-alive是爲了讓tcp活得更久一點,以便在同一個鏈接上傳送多個http,提升socket的效率。而tcp keep-alive是TCP的一種檢測TCP鏈接情況的保鮮機制。tcp keep-alive保鮮定時器,支持三個系統內核配置參數:
1 echo 1800 > /proc/sys/net/ipv4/tcp_keepalive_time 2 echo 15 > /proc/sys/net/ipv4/tcp_keepalive_intvl 3 echo 5 > /proc/sys/net/ipv4/tcp_keepalive_probes
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鏈接。通常不會出現這種狀況,除非你須要這樣作。
使用http keep-alvie,能夠減小服務端TIME_WAIT數量(由於由服務端httpd守護進程主動關閉鏈接)。道理很簡單,相較而言,啓用keep-alive,創建的tcp鏈接更少了,天然要被關閉的tcp鏈接也相應更少了。
我想用一張示意圖片來講明使用啓用keepalive的不一樣。另外,http keepalive是客戶端瀏覽器與服務端httpd守護進程協做的結果,因此,咱們另外安排篇幅介紹不一樣瀏覽器的各類狀況對keepalive的利用。
故名思意,Conent-Length表示實體內容長度,客戶端(服務器)能夠根據這個值來判斷數據是否接收完成。可是若是消息中沒有Conent-Length,那該如何來判斷呢?又在什麼狀況下會沒有Conent-Length呢?請繼續往下看……