關於Keepalive的那些事

服務端很多同學包括自己對keepalive理解不清晰,經常搞不清楚,TCP也有keepalive,HTTP也有keepalive,高可用也叫keepalive,經常混淆這幾個概念。做下這幾個概念的簡述,儘管名字基本上是一樣的,但是所表示意義和範疇卻大相徑庭。

高可用 Keepalived

Keepalived是一個基於VRRP協議來實現的服務高可用方案,可以利用其來避免IP單點故障。它的作用是檢測服務器的狀態,如果有一臺服務器宕機,或出現故障,Keepalived將檢測到,使用其他服務器代替該服務器的工作,當服務器工作正常後Keepalived自動將服務器加入到服務器羣中。
Keepalived一般不會單獨出現,而是與其它負載均衡技術(如lvs、haproxy、nginx)一起工作來達到集羣的高可用。

一個簡單的使用例子,將域名解析到一臺負載均衡機器上,然後負載均衡反向代理到WEB機器上。中間的負載均衡只有一臺,沒法做到高可用,至少需要做到兩臺,那配置成兩臺機器之後,Keepalived就可以保證服務只有一個對外的虛擬IP,如果MASTER的負載均衡出現故障的時候,自動切換到BACKUP負載均衡上,服務不受任何影響。Keepalived來保證這些。

我們以前有過一套稍顯複雜的服務配置,Keepalived給HAProxy提供高可用,然後HAProxy給Twemproxy提供高可用和負載均衡,Twemproxy給Redis集羣提供高可用和負載均衡。提供負載均衡服務的基本都會保證高可用,我們使用最多的Nginx作爲反向代理服務器的時候,就能保證web服務的高可用。

nginx+keepalived 搭建高可用的服務教程有很多。感興趣的可以自己試下搭建。

TCP 的keepalive

TCP的keepalive主要目的是及時的釋放服務器資源。
通過TCP協議客戶端與服務器建立連接之後,如果客戶端一直不發送數據,或者隔很長時間才發送一次數據,當連接很久沒有數據傳輸時如何去確定對方還在線,到底是掉線了還是確實沒有數據傳輸,連接是保持還是關閉,多長時間或者在什麼樣的機制下連接應該關閉釋放資源。TCP的keepalive就是爲了解決這個問題才引入的。
TCP的keepalive主要是三個參數來控制

tcp_keepalive_time 7200
心跳週期
tcp_keepalive_intvl 75
偵測包發送間隔
tcp_keepalive_probes 9
偵測包重試次數

解釋下這個流程和參數。
客戶端與服務器建立連接後,如果雙方在tcp_keepalive_time(7200S)後,沒有任何數據的傳輸,服務器就會每隔tcp_keepalive_intvl(75S)向客戶端發送探測包,判斷客戶端的連接狀態,大概包括客戶端崩潰、強制關閉了應用、主機不可達等的異常狀態。如果偵測包發送了tcp_keepalive_probes(9)次之後仍然沒有收到客戶端的回覆(就是ack包),服務器就會認爲這個連接已經不可用了,可以丟棄或者關閉了。

Nginx 的keepalive

TCP層已經有keepalive,爲什麼應用層的Nginx還需要keepalive?
我理解的是,使用TCP的keepalive的保證傳輸層連接的可用性,默認配置都是2小時的檢測週期。Nginx的keepalive來保證應用層的連接的可用性。一個在第四層傳輸層上保證可用性,一個在第七層應用層上保證應用層協議連接的可用性。
有本書裏面有提到:
爲什麼TCP keepalive不能替代應用層心跳?心跳除了說明應用程序還活着(進程還在,網絡通暢),更重要的是表明應用程序還能正常工作。而TCP keepalive由操作系統負責探查,即便進程死鎖或者阻塞,操作系統也會如常收發TCP keepalive信息,對方無法得知這一異常。

nginx keepalive跟TCP的配置基本一致,只不過名字不一樣罷了。配置說明如下

so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt] 

so_keepalive=30m::10 表示開啓tcp偵測,30分鐘後無數據收發會發送偵測包,時間間隔使用系統默認的,發送10次偵測包。

HTTP的keepalive

HTTP的keepalive比較常見,就是將短鏈接變成長鏈接。短連接是每個請求響應,客戶端和服務器都要新建一個連接,完成之後立即斷開連接;當使用keepalive長連接時,客戶端到服務器端的建立連接,響應完成後連接不斷開,下次請求直接服用原來的連接,這樣就避免了重複建立連接和斷開連接的開銷。

那麼客戶端和服務器端是怎麼約定使用長連接通信還是短連接通信。
主要Connection頭部

客戶端請求長連接頭部:Connection: keep-alive
服務端同意使用長連接的響應頭部:Connection: keep-alive
兩者缺一不可,如果服務器端不支持長連接:Connection: Close
如果是HTTP/1.1默認使用長連接,無論頭部是不是 Connection: keep-alive

注意的點:
Connection只對當前的連接雙方有效,並且Connection頭部不向後傳遞,只標識自己的連接狀態。
如果是多級代理又是什麼流程?
在這裏插入圖片描述
1客戶端與代理服務器1建連的時候帶了Connection: keep-alive,但是代理服務器1不支持長連接,回覆了Connection: Close,所以使兩者用短連接
2代理服務器1與代理服務器2建連的時候使用Connection: Close短連接,代理服務器2回覆了Connection: Close,所以兩者使用短連接
3代理服務器2與web機器建連的時候使用了Connection: keep-alive,web機器支持長連接,也回覆了Connection: keep-alive,所以兩者使用長連接

HTTP的keepalive是開發者最長遇到的,所以要格外注意。不是服務器要求使用長連接連接就是長連接,是需要雙方都同意才能使用長連接通信。以前遇到過阿里雲的SLB就不支持長連接,WEB服務器或者代理服務器跟SLB連接的都是短連接。

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