Keepalived主要是通過虛擬路由冗餘來實現高可用功能。本文將不對keepalived的基本原理進行闡述,可參考文章Keepalived詳細介紹簡介、keepalived vip漂移基本原理及選舉算法。本文記錄了在實踐過程中使用keepalived時,在weight值變化的情況下vip不漂移的問題及解決方法。
場景
3個keepalived節點, vip爲172.31.23.6:
- devops1a-zoocassa0 172.31.23.22
- devops1a-zoocassa1 172.31.23.23
- devops1a-zoocassa2 172.31.23.24
預期
- 三個節點初始都設爲BACKUP,按照優先級(priority)選舉MASTER;
- 在三個節點上檢查memcached服務狀態,失敗則降低優先級;
- 如果MASTER(假設爲devops1a-zoocassa0)上檢查失敗,BACKUP上檢查成功,則優先級高的BACKUP節點(假設爲devops1a-zoocassa1)切換爲MASTER節點;
- 之前檢查失敗的MASTER(devops1a-zoocassa0)上的服務恢復時, 之前的BACKUP節點(devops1a-zoocassa1)服務檢查也成功,即使devops1a-zoocassa0優先級恢復到高於devops1a-zoocassa1,也不再成爲MASTER(不搶佔)。
不成功配置範例
# devops1a-zoocassa0
vrrp_script chk_memcached {
script "killall -0 memcached" #檢查memcached服務
interval 5
weight 3
}
vrrp_instance VI_1 {
interface eth0
state BACKUP
virtual_router_id 55
nopreempt #設置不搶佔
priority 101
unicast_src_ip 172.31.23.22
unicast_peer {
172.31.23.23
172.31.23.24
}
virtual_ipaddress {
172.31.23.6
}
track_script {
chk_memcached
}
}
# devops1a-zoocassa1
vrrp_script chk_memcached {
script "killall -0 memcached"
interval 5
weight 3
}
vrrp_instance VI_1 {
interface eth0
state BACKUP
virtual_router_id 55
nopreempt
priority 100
unicast_src_ip 172.31.23.23
unicast_peer {
172.31.23.22
172.31.23.24
}
virtual_ipaddress {
172.31.23.6
}
track_script {
chk_memcached
}
}
# devops1a-zoocassa2
vrrp_script chk_memcached {
script "killall -0 memcached"
interval 5
weight 3
}
vrrp_instance VI_1 {
interface eth0
state BACKUP
virtual_router_id 55
nopreempt
priority 99
unicast_src_ip 172.31.23.24
unicast_peer {
172.31.23.22
172.31.23.23
}
virtual_ipaddress {
172.31.23.6
}
track_script {
chk_memcached
}
}
以上述配置文件內容作爲keepalived配置文件/etc/keepalived/keepalived.conf,在三個節點上啓動keepalived:
service keepalived start
會發現存在如下問題:
- 優先級高的devops1a-zoocassa0可能沒有成爲MASTER節點(多試幾次,可能每次選舉的MASTER節點都不同),不符合預期中的第1點;
- 假設devops1a-zoocassa0成爲了MASTER節點,關掉devops1a-zoocassa0上的memcached服務:
service memcached stop
此時運行service keepalived status,發現devops1a-zoocassa0的weight值降低且低於devops1a-zoocassa1,但是devops1a-zoocassa1並沒有成爲MASTER節點,不符合預期中的第3點。
-
將配置文件中的nopreempt去掉以後,可以解決上述問題,符合預期中的第1,2,3點,但是當原MASTER節點上服務恢復後,原MASTER會重新成爲MASTER角色,這不符合預期中的第4點(不搶佔);
問題原因:
在網上查閱到的資料中,大都認爲按照上述配置後可以完全符合預期中的4個點,不會出現MASTER節點服務檢查失敗後VIP不漂移的問題。但是實踐是檢驗真理的唯一標準,配置nopreemt後,不僅是會讓原MASTER節點服務恢復後不搶佔,而是會完全的不選舉新MASTER(從頭到尾永遠不切換,除非BACKUP認爲當前集羣中不存在MASTER, 纔會重新選舉),這樣便可以解釋出現的問題1和問題2了:
問題1的原因在於:
- 先啓動的節點將自己選舉爲MASTER, 在收到其他節點的vrrp報文後不會按照優先級調整自己的角色;
- 後啓動的節點收到了MASTER的vrrp報文,發現已經存在MASTER,由於不搶佔,自動進入BACKUP狀態;
問題2的原因在於:
- 設置了nopreempt, 永遠不發生角色切換;
下面是官方文檔中對於nopreempt的解釋:
"nopreempt" allows the lower priority machine to maintain the master role,
even when a higher priority machine comes back online.
NOTE: For this to work, the initial state of this entry must be BACKUP.
解決方案
要想同時滿足預期中的效果,其實只要做到兩點:
- 當MASTER上的服務檢查失敗時,觸發重新選舉;
- 設置不搶佔(已經做到);
那麼如何實現第一點呢?重新選舉意味着:
- BACKUP成爲MASTER,要求BACKUP節點認爲當前節點中沒有MASTER節點;
- MASTER成爲BACKUP,要求MASTER節點感知到環境中存在別的MASTER節點,從而進入BACKUP狀態;
節點之間通過VRRP報文獲得相互的優先級及狀態信息,因此,可以通過在服務檢查失敗時,配置防火牆,禁止本機的VRRP報文發出即可。這樣,BACKUP節點收不到MASTER節點的VRRP報文,認爲MASTER節點不存在,同時MASTER節點能收到其他節點的VRRP報文,感知到新MASTER的產生,從而進入BACKUP狀態。
配置如下(僅以devops1a-zoocassa0爲例,其他節點類推):
# devops1a-zoocassa0 /etc/keepalived/keepalived.conf
vrrp_script chk_memcached {
script "/etc/keepalived/check_memcached.sh"
interval 5
weight 3
}
vrrp_instance VI_1 {
interface eth0
state BACKUP
virtual_router_id 55
nopreempt
priority 101
unicast_src_ip 172.31.23.22
unicast_peer {
172.31.23.23
172.31.23.24
}
virtual_ipaddress {
172.31.23.6
}
track_script {
chk_memcached
}
}
# devops1a-zoocassa0 /etc/keepalived/chk_memcached.sh
#!/bin/bash
killall -0 memcached #檢查memcached服務
if [[ $? == 0 ]];then #檢查成功
/sbin/iptables -L | grep vrrp
if [[ $? == 0 ]]; then #如果iptable中有vrrp的配置,刪除它
/sbin/iptables -D OUTPUT -p vrrp -j DROP
fi
exit 0
else #檢查失敗
/sbin/iptables -L | grep vrrp
if [[ $? != 0 ]]; then
/sbin/iptables -A OUTPUT -p vrrp -j DROP #如果iptable中沒有vrrp的條目,禁止vrrp發出
fi
exit 1
fi
重啓keepalived服務,測試成功。