轉載:https://www.cnblogs.com/hukey/p/5481173.html
TCP Keepalive
Tcp Keepalive的起源
雙方建立交互的連接,但是並不是一直存在數據交互,有些連接會在數據交互完畢後,主動釋放連接,而有些不會,那麼在長時間無數據交互的時間段內,交互雙方都有可能出現掉電、死機、異常重啓等各種意外,當這些意外發生之後,這些TCP連接並未來得及正常釋放,那麼,連接的另一方並不知道對端的情況,它會一直維護這個連接,長時間的積累會導致非常多的半打開連接,造成端系統資源的消耗和浪費,爲了解決這個問題,在傳輸層可以利用TCP的保活報文來實現。
Tcp Keepalive存在的作用
1.探測連接的對端是否存活
在應用交互的過程中,可能存在以下幾種情況:
(1) 客戶端或服務端意外斷電,死機,崩潰,重啓。
(2) 中間網絡已經中斷,而客戶端與服務器並不知道。
利用保活探測功能,可以探知這種對端的意外情況,從而保證在意外發生時,可以釋放半打開的TCP、
連接。
2.防止中間設備因超時刪除連接相關的連接表
中間設備如防火牆等,會爲經過它的數據報文建立相關的連接信息表,並未其設置一個超時時間的定時器,如果超出預定時間,某連接無任何報文交互的話,中間設備會將該連接信息從表中刪除,在刪除後,再有應用報文過來時,中間設備將丟棄該報文,從而導致應用出現異常,這個交互的過程大致如下圖所示:
這種情況在有防火牆的應用環境下非常常見,這會給某些長時間無數據交互但是又要長時間維持連接的應用(如數據庫)帶來很大的影響,爲了解決這個問題,應用本身或TCP可以通過保活報文來維持中間設備中該連接的信息,(也可以在中間設備上開啓長連接屬性或調高連接表的釋放時間來解決,但是,這個影響可能較大,有機會再針對這個做詳細的描述,在此不多說)。
常見應用故障場景:
某財務應用,在客戶端需要填寫大量的表單數據,在客戶端與服務器端建立TCP連接後,客戶端終端使用者將花費幾分鐘甚至幾十分鐘填寫表單相關信息,
終端使用者終於填好表單所需信息後,點擊“提交”按鈕,結果,這個時候由於中間設備早已經將這個TCP連接從連接表中刪除了,
其將直接丟棄這個報文或者給客戶端發送RST報文,應用故障產生,這將導致客戶端終端使用者所有的工作將需要重新來過,給使用者帶來極大的不便和損失。
TCP保活報文交互過程
TCP保活的交互過程大致如下圖所示:
TCP保活可能帶來的問題
1.中間設備因大量保活連接,導致其連接表滿
網關設備由於保活問題,導致其連接表滿,無法新建連接(XX局網閘故障案例)或性能下降嚴重
2.正常連接被釋放
當連接一端在發送保活探測報文時,中間網絡正好由於各種異常(如鏈路中斷、中間設備重啓等)而無法將保活探測報文正確轉發至對端時,可能會導致探測的一方釋放本來正常的連接,但是這種可能情況發生的概率較小,另外,一般也可以增加保活探測報文發生的次數來減少這種情況發生的概率和影響。
HTTP Keepalive
Httpd守護進程,一般都提供了keep-alive timeout時間設置參數。比如nginx的keepalive_timeout,和Apache的KeepAliveTimeout。
這個keepalive_timeout時間值意味着:一個http產生的tcp連接在傳送完最後一個響應後,還需要hold住keepalive_timeout秒後,纔開始關閉這個連接。
當httpd守護進程發送完一個響應後,理應馬上主動關閉響應的tcp連接,設置keepalive_timeout後,httpd守護進程會想說:"再等等吧,看看瀏覽器還有沒有請求過來",這一等,便是keepalive_timeout時間。如果守護進程在這個等待的時間裏,一直沒有收到瀏覽器發過來http請求,則關閉這個http連接。
1.在沒有設置keepalive_timeout情況下,一個socket資源從建立到真正釋放需要經過的時間是:建立tcp連接+傳送http請求+php腳本執行+傳送http響應+關閉tcp連接
2.設置了keepalive_timeout時間情況下,一個socket建立到釋放需要的時間是多了keepalive_timeout時間。
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保險定時器,支持三個系統內核配置參數:
echo 1800 > /proc/sys/net/ipv4/tcp_keepalive_time
echo 15 > /proc/sys/net/ipv4/tcp_keepalive_intvl
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連接。
一般不會出現這種情況,除非你需要這樣做。
keep-alive與TIME_WAIT
使用http keep-alive,可以減少服務端TIME_WAIT數量(因爲由服務端httpd守護進程主動關閉連接)。道理很簡單,相較而言,啓用keep-alive,建立的tcp連接更少了,自然要被關閉的tcp連接也相應更少了。