服務端很多同學包括自己對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連接的都是短連接。