Keepalive詳解
工作原理
Keepalived本質就是為ipvs服務的,它也不需要共享存儲。IPVS其實就是一些規則,Keepalived主要的任務就是去調用ipvsadm命令,來生成規則,並自動實現將用戶需要訪問的地址轉移到可用LVS節點實現。所以keepalive的高可用是屬於具有很強針對性的高可用,它和corosync這種通用性HA方案不同。
Keepalived的主要目的就是它自身啟動為一個服務,它工作在多個LVS主機節點上,當前活動的節點叫做Master備用節點叫做Backup,Master會不停的向Backup節點通告自己的心跳,這種通告是基於VRRP協議的。Backup節點一旦接收不到Master的通告信息,它就會把LVS的VIP拿過來,並且把ipvs的規則也拿過來,在自己身上生效,從而替代Master節點。
Keepalived除了可以監控和轉移LVS資源之外,它還可以直接配置LVS而不需要直接使用ipvsadm命令,因為它可以調用,也就是說在LVS+KEEPALIVED模型中,你所有的工作在Keepalived中配置就可以了,而且它還有對后端應用服務器健康檢查的功能。
直接一句話Keepalived就是VRRP協議的實現,該協議是虛擬冗余路由協議。
VRRP工作原理簡述
那么這個VRRP協議是干嘛用呢?傳統上來說我們通過一個路由器上網,如果故障那就不能用了,如果使用2個路由器,有一個故障你就需要手動的設置客戶端切換到另外的路由器上,或者使用ARP客戶端也可以實現,但總之部署比較麻煩不利於管理,就像下圖:
有沒有一種辦法可以自動轉移而省去手動配置呢?我們就可以通過VRRP協議來實現路由器的故障轉移。如下圖:
這里有個問題,VRRP提供一個VIP,它可以來設定那個路由器是活動節點,然后出現故障進行切換,VIP也隨之對應到新的路由器上,但是內網是用過MAC地址來尋址的,雖然VIP對應到了新的路由器上,可是MAC變了,客戶端的ARP表也沒有更新,所以還是用不了,為了解決這個問題VRRP不但提供VIP還提供VMAC地址,這個VMAC地址是VRRP單獨申請的,大家都可以正常使用。
故障切換的時候雖然改變了后端路由器,但是由於客戶端使用的是VIP和VMAC地址,這樣就不會有任何影響了。
所以Keepalived就是在Linux系統上提供了VRRP功能,當然還提供了服務監控功能,比如監控后端服務器的健康檢查、LVS服務可用性檢查。
VRRP的工作過程是這樣的:
- 虛擬路由器中的路由器根據優先級選舉出Master,Master路由器通過發送免費ARP報文,將自己的虛擬MAC地址通告給與它連接的設備。
- Master路由器周期性發送VRRP報文,以公布自己的配置信息(優先級等)和工作狀態
- 如果Master故障,虛擬路由器中的Backup路由器將根據優先級重新選舉新的Master
- 虛擬路由器狀態切換時,Master路由器由一台設備切換會另外一台設備,新的Master路由器只是簡單的發送一個攜帶虛擬MAC地址和虛擬IP的免費ARP報文,這樣就可以更新其他設備中緩存的ARP信息
- Backup路由器的優先級高於Master時,由Backup的工作方式(搶占式或者非搶占式)決定是否重新選舉Master。
VRRP還支持認證,就是為了防止隨意一個VRRP設備加入到當前的虛擬路由組離來,它提供無認證、簡單8位字符串認證和MD5認證(該認證方式Keepalive不支持)。
Keepalive軟件結構
Keepalived啟動后以后會有一個主進程Master,它會生成還有2個子進程,一個是VRRP Stack負責VRRP(也就是VRRP協議的實現)、一個是Checkers負責IPVS的后端的應用服務器的健康檢查,當檢測失敗就會調用IPVS規則刪除后端服務器的IP地址,檢測成功了再加回來。當檢測后端有失敗的情況可以使用SMTP通知管理員。另外VRRP如果檢測到另外一個Keepalive失敗也可以通過SMTP通知管理員。
Control Plane:這個就是主進程,主進程的功能是分析配置文件,讀取、配置和生效配置文件,指揮那2個子進程工作。
WatchDog:看門狗,這個是Linux系統內核的一個模塊,它的作用是幫助主進程盯着那2個子進程,因為主進程並不負責具體工作,具體工作都是子進程完成的。如果子進程掛了,那Keepalived就不完整了,所以那2個子進程會定期的向主進程打開的一個內部Unix Socket文件寫心跳信息。如果有某個子進程不寫信息了,它就會重啟子進程,主進程就是讓WatchDog來監控子進程的。下面我們就使用Keepalive來做LVS的高可用講解。關於后端服務器上的設置我這里就不說了請看另外一篇博文。
Keepalive安裝和配置
服務器 | IP地址 | 角色 |
---|---|---|
Srv01 | 172.16.42.100 VIP: 172.16.42.111 |
LVS+Keepalive |
Srv02 | 172.16.42.101 VIP: 192.168.100.1 |
LVS+Keepalive |
Srv03 | 172.16.42.102 VIP: 172.16.42.111 |
Nginx |
Srv04 | 172.16.42.103 VIP: 172.16.42.111 |
Nginx |
先決條件
-
禁用SElinux、清除iptables規則、關閉防火牆。就算因某種原因不能清除iptables規則,那么你需要增加一條規則放行多播
-
各個節點時間同步,啟用時間同步服務
systemctl start chronyd
-
確保Keepalive使用的網卡開啟了多播,如下圖:
如果沒有開啟,可以使用該命令打開ip link set multicast on dev ens33
,ens33是網卡名稱。
安裝keepalive
之間通過yum安裝即可yum install -y keepalived
。我這里使用的是阿里雲的源,它默認就在里面,如下圖:
在2個節點都安裝。
文件 | 說明 |
---|---|
/usr/sbin/keepalived | 二進制程序 |
/etc/keepalived/keepalived.conf | 配置文件 |
/usr/lib/systemd/system/keepalived.service | 服務文件 |
Keepalive配置文件說明
# 全局配置
global_defs {
# 郵件通知信息
notification_email {
# 定義收件人
acassen@firewall.loc
}
# 定義發件人
notification_email_from Alexandre.Cassen@firewall.loc
# SMTP服務器地址
smtp_server 192.168.200.1
smtp_connect_timeout 30
# 路由器標識,一般不用改,也可以寫成每個主機自己的主機名
router_id LVS_DEVEL
# VRRP的ipv4和ipv6的廣播地址,配置了VIP的網卡向這個地址廣播來宣告自己的配置信息,下面是默認值
vrrp_mcast_group4 224.0.0.18
vrrp_mcast_group6 ff02::12
}
# 定義用於實例執行的腳本內容,比如可以在線降低優先級,用於強制切換
vrrp_script SCRIPT_NAME {
}
# 一個vrrp_instance就是定義一個虛擬路由器的,實例名稱
vrrp_instance VI_1 {
# 定義初始狀態,可以是MASTER或者BACKUP
state MASTER
# 工作接口,通告選舉使用哪個接口進行
interface ens33
# 虛擬路由ID,如果是一組虛擬路由就定義一個ID,如果是多組就要定義多個,而且這個虛擬
# ID還是虛擬MAC最后一段地址的信息,取值范圍0-255
virtual_router_id 51
# 使用哪個虛擬MAC地址
use_vmac XX:XX:XX:XX:XX
# 監控本機上的哪個網卡,網卡一旦故障則需要把VIP轉移出去
track_interface {
eth0
ens33
}
# 如果你上面定義了MASTER,這里的優先級就需要定義的比其他的高
priority 100
# 通告頻率,單位為秒
advert_int 1
# 通信認證機制,這里是明文認證還有一種是加密認證
authentication {
auth_type PASS
auth_pass 1111
}
# 設置虛擬VIP地址,一般就設置一個,在LVS中這個就是為LVS主機設置VIP的,這樣你就不用自己手動設置了
virtual_ipaddress {
# IP/掩碼 dev 配置在哪個網卡
192.168.200.16/24 dev eth1
# IP/掩碼 dev 配置在哪個網卡的哪個別名上
192.168.200.17/24 dev label eth1:1
}
# 虛擬路由,在需要的情況下可以設置lvs主機 數據包在哪個網卡進來從哪個網卡出去
virtual_routes {
192.168.110.0/24 dev eth2
}
# 工作模式,nopreempt表示工作在非搶占模式,默認是搶占模式 preempt
nopreempt|preempt
# 如果是搶占默認則可以設置等多久再搶占,默認5分鍾
preempt delay 300
# 追蹤腳本,通常用於去執行上面的vrrp_script定義的腳本內容
track_script {
}
# 三個指令,如果主機狀態變成Master|Backup|Fault之后會去執行的通知腳本,腳本要自己寫
notify_master ""
notify_backup ""
notify_fault ""
}
# 定義LVS集群服務,可以是IP+PORT;也可以是fwmark 數字,也就是防火牆規則
# 所以通過這里就可以看出來keepalive天生就是為ipvs而設計的
virtual_server 10.10.10.2 1358 {
delay_loop 6
# 算法
lb_algo rr|wrr|lc|wlc|lblc|sh|dh
# LVS的模式
lb_kind NAT|DR|TUN
# 子網掩碼,這個掩碼是VIP的掩碼
nat_mask 255.255.255.0
# 持久連接超時時間
persistence_timeout 50
# 定義協議
protocol TCP
# 如果后端應用服務器都不可用,就會定向到那個服務器上
sorry_server 192.168.200.200 1358
# 后端應用服務器 IP PORT
real_server 192.168.200.2 1358 {
# 權重
weight 1
# MSIC_CHECK|SMTP_CHEKC|TCP_CHECK|SSL_GET|HTTP_GET這些都是
# 針對應用服務器做健康檢查的方法
MISC_CHECK {}
# 用於檢查SMTP服務器的
SMTP_CHEKC {}
# 如果應用服務器不是WEB服務器,就用TCP_CHECK檢查
TCP_CHECK {
# 向哪一個端口檢查,如果不指定默認使用上面定義的端口
connect_port <PORT>
# 向哪一個IP檢測,如果不指定默認使用上面定義的IP地址
bindto <IP>
# 連接超時時間
connect_timeout 3
}
# 如果對方是HTTPS服務器就用SSL_GET方法去檢查,里面配置的內容和HTTP_GET一樣
SSL_GET {}
# 應用服務器UP或者DOWN,就執行那個腳本
notify_up "這里寫的是路徑,如果腳本后有參數,整體路徑+參數引起來"
notify_down "/PATH/SCRIPTS.sh 參數"
# 使用HTTP_GET方法去檢查
HTTP_GET {
# 檢測URL
url {
# 具體檢測哪一個URL
path /testurl/test.jsp
# 檢測內容的哈希值
digest 640205b7b0fc66c1ea91c463fac6334d
# 除了檢測哈希值還可以檢測狀態碼,比如HTTP的200 表示正常,兩種方法二選一即可
status_code 200
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
# 向哪一個端口檢查,如果不指定默認使用上面定義的端口
connect_port <PORT>
# 向哪一個IP檢測,如果不指定默認使用上面定義的IP地址
bindto <IP>
# 連接超時時間
connect_timeout 3
# 嘗試次數
nb_get_retry 3
# 每次嘗試之間間隔幾秒
delay_before_retry 3
}
}
real_server 192.168.200.3 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334c
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334c
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}
配置Srv01和Srv02
配置VRRP部分
Srv01上的keepalived.conf
global_defs {
notification_email {
acassen@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id srv01
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.16.42.111/24 brd 172.16.42.111 dev ens33 label ens33:0
}
preempt delay 60
}
Srv02上的keepalived.conf,唯一不同的就是state、priority以及router_id。
global_defs {
notification_email {
acassen@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id srv02
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.16.42.111/24 brd 172.16.42.111 dev ens33 label ens33:0
}
preempt delay 60
}
啟動2個節點,啟動后會自動配置ens33:0這個子接口的虛擬IP
在主節點上你通過systemctl status keepalived
看不到它到底是什么角色,不過在BACKUP節點上你可以看到,但是你在主節點日志中cat /var/log/message
里可以看到Srv01進入到MASTER狀態,如下圖:
查看Srv02的狀態
那么你通過停止Srv01上的keepalived服務就看到MASTER會被轉移到Srv02上。
使用該命令查看VRRP通告tcpdum -i ens33 -nn host 224.0.0.18
,你在2台主機都會看到相同的信息。
Srv01使用真實物理IP對該地址進行發送通告,那么Srv02也會收到,如果Srv01宕機,那么Srv02就會使用自己的物理IP向該地址發送通告,由於Srv01已經宕機那么此時Srv02的優先級就是最高的,所以Srv02就變成了MASTER。
配置LVS部分
這里只是用了LVS來說明如何配置Keepalived,如果要看完整內容請移步使用Keepalived構建LVS高可用集群
在keepalived.conf文件中增加下面的內容,2台服務器增加的內容一致,所以這里就寫一份。
virtual_server 172.16.42.111 80 {
delay_loop 6
lb_algo rr
lb_kind DR
nat_mask 255.255.255.0
persistence_timeout 0
protocol TCP
sorry_server 192.168.200.200 1358
# 后端應用服務器 IP PORT
real_server 172.16.42.102 80 {
weight 1
# 應用服務器UP或者DOWN,就執行那個腳本
notify_up "/usr/local/notify.sh up"
notify_down "/usr/local/notify.sh down"
HTTP_GET {
# 檢測URL
url {
path /index.html
# 除了檢測哈希值還可以檢測狀態碼,比如HTTP的200 表示正常,兩種方法二選一即可
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
real_server 172.16.42.103 80 {
weight 1
# 應用服務器UP或者DOWN,就執行那個腳本
notify_up "/usr/local/notify.sh up"
notify_down "/usr/local/notify.sh down"
HTTP_GET {
# 檢測URL
url {
path /index.html
# 除了檢測哈希值還可以檢測狀態碼,比如HTTP的200 表示正常,兩種方法二選一即可
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}
這里的notify_up|down腳本我寫的很簡單就是為了使用一下這個功能,內容如下:
#!/bin/bash
# 不同的是2個主機上的echo部分不一樣,因為主機名不同。
if [ $1 == "up" ]; then
echo "Srv02 is UP" > /tmp/notify.txt
elif [ $1 == "down" ]; then
echo "Srv02 is DOWN" > /tmp/notify.txt
fi
重啟Keepalived服務之后你就可以通過ipvsadm -Ln
查看ipvs規則了,這些規則在2台服務器上都會有,如下圖:
測試訪問
使用下面的命令快速訪問for i in {1..20}; do curl http://172.16.42.111/ | grep "Srv0" --color ; done
可以看到2台服務器交替,因為我們使用的rr調度算法。
故障轉移測試
連續訪問VIP,然后停止Srv01上面的keepalived服務,這就意味着Srv01也就是失去了VIP,然后觀察請求情況以及是否觸發之前設定的腳本。
在Srv01上查看腳本執行情況
查看Srv02上面的日志