之前有寫過redis+sentinel的哨兵機制主從的切換,這一次多了一個keepalived,是爲了能夠方便項目只支持一臺訪問,可是又要高可用的情況下,就可以執行此方案。
本次主要講的就是keepalived的配置,如何才能做到單臺訪問而實現高可用,從而實現主從無縫切換。
1.有個問題需要注意
當master down了,backup接管了,master再次起來,不能再成爲master。否則master恢復了再接管的話,會造成業務來回切換,這時候就需要nopreempt參數了。
nopreempt:設置不搶佔,這裏只能設置在state爲backup的節點上,而且這個節點的優先級必須別另外的高。
先來看看方案的整體思路:
通過keepalived的自定義腳本功能監控本機的redis服務狀態,當監控腳本檢測到redis服務出現異常時,則改變本機keepalived的優先級,同時這會導致master/backup角色的變化,而keepalived在角色變化時也會觸發一些機制執行相關腳本,這就爲我們改變redis的master/slave狀態提供了機會,這樣做的目的是爲了是redis的master/slave直接的數據保持一致。
在keepalived+redis的使用過程中有三種情況:
1 一種是keepalived掛了,同時redis也掛了,這樣的話直接VIP飄走之後,通過哨兵對redis數據同步,並切換主從,哨兵集羣會自動去切換,保證數據的一致性。
2 另一種是keepalived掛了,redis沒掛,這時候VIP飄走後,redis的master/slave還是老的對應關係,如果不變化的話會把數據寫入redis slave中,從而不會同步到master上去,這就要藉助監控腳本反轉redis的master/slave關係。這時候就要預留一點時間進行數據同步,然後反轉master/slave。
3 還有一種是keepalived沒掛,redis掛了,這時候根據監控腳本會檢測到redis掛了,並且降低keepalived master的優先級,同樣會導致VIP飄走,情況和第二種一樣,也是需要進行數據同步,然後反轉當前redis的master/slave關係的。
進入正題,安裝keepalived的過程就略了,安裝redis的也跳過,直接將keepalived的配置文件。
一.配置主keepalived
! Configuration File for keepalived
global_defs {
lvs_id LVS_redis
}
vrrp_script chk_redis {
script "/etc/keepalived/scripts/redis_check.sh" #執行指定腳本
weight -20 #腳本結果導致的優先級變更:20表示優先級+20;-20則表示優先級-20
interval 2 #指定腳本的執行時間間隔
}
vrrp_instance VI_1 {
state backup
interface eth0 #把vip掛再哪個網卡上
virtual_router_id 51
nopreempt #不搶佔資源,只有在主的keepalived設置
priority 200 #權重值
advert_int 5
track_script {
chk_redis
}
virtual_ipaddress {
192.168.18.230 #設置VIP
}
notify_master /etc/keepalived/scripts/redis_master.sh
notify_backup /etc/keepalived/scripts/redis_backup.sh
notify_fault /etc/keepalived/scripts/redis_fault.sh
notify_stop /etc/keepalived/scripts/redis_stop.sh
}
二.建立主redis切換狀態腳本
在/etc/keepalived目錄下建立log和scripts目錄。
在script下有五個腳本,一個是檢測redis狀態的redis_check.sh腳本,其餘四個是keepalived狀態變化時執行的腳本。keepalived有master/backup/stop/fault四種狀態,因爲我們主要是關注系統上的業務,所以在在keepalived進入fault/stop狀態後,也認爲是進入了backup狀態,需要對redis的master/slave關係進行反轉,否則即使VIP漂移過去,但是redis的主從關係還沒有改變,會導致數據不一致,所以最終四個腳本只有兩種內容。
(1)檢測腳本redis_check.sh (主從這裏配置都一樣)
#!/bin/bash
###/etc/keepalived/scripts/redis_check.sh
ALIVE=`/opt/redis/src/redis-cli PING` #參考使用只修改redis-cli的路徑即可
if [ "$ALIVE" == "PONG" ]; then
echo $ALIVE
exit 0
else
echo $ALIVE
exit 1
fi
(2)keepalived進入master狀態時的檢測腳本redis_master.sh
#!/bin/bash
###/etc/keepalived/scripts/redis_master.sh
REDISCLI="/opt/redis/src/redis-cli" #修改redis-cli的位置,如有做變量,則直接輸入爲"redis-cli"即可
LOGFILE="/etc/keepalived/log/redis-state.log" #生成日誌路徑
pid=$$
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[slaver]" >> $LOGFILE
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[slaver] Run 'SLAVEOF 192.168.18.137 6379'" >> $LOGFILE #修改下從redis的IP即可
$REDISCLI SLAVEOF 192.168.18.137 6379 >> $LOGFILE 2>&1 #修改下從redis的IP即可
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[slaver] wait 10 sec for data sync from old master" >> $LOGFILE
sleep 10
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[slaver] data rsync from old mater ok..." >> $LOGFILE
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master] Run slaveof no one,close master/slave" >> $LOGFILE
$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master] wait other slave connect...." >> $LOGFILE
(3)keepalived進入backup時的檢測腳本(stop和fault的腳本跟backup腳本一致,所以CP修改下名稱即可)
#!/bin/bash
###/etc/keepalived/scripts/redis_backup.sh
REDISCLI="/opt/redis/src/redis-cli"
LOGFILE="/etc/keepalived/log/redis-state.log"
pid=$$
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master]" >> $LOGFILE
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master] Being slave state..." >> $LOGFILE 2>&1
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master] wait 10 sec for data sync from old master" >> $LOGFILE
sleep 10
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master] data rsync from old mater ok..." >> $LOGFILE
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[slaver] Run 'SLAVEOF 192.168.18.137 6379'" >> $LOGFILE #修改從redis的IP即可
$REDISCLI SLAVEOF 192.168.18.137 6379 >> $LOGFILE 2>&1
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[slaver] slave connect to 192.168.18.137 ok..." >> $LOGFILE #修改從redis的IP即可
三.從keepalived配置文件配置
! Configuration File for keepalived
global_defs {
lvs_id LVS_redis
}
vrrp_script chk_redis {
script "/etc/keepalived/scripts/redis_check.sh"
weight -20
interval 2
}
vrrp_instance VI_1 {
state backup
interface eth0
virtual_router_id 51
priority 190 #權重值要比主的低
advert_int 5
track_script {
chk_redis
}
virtual_ipaddress {
192.168.18.230
}
notify_master /etc/keepalived/scripts/redis_master.sh
notify_backup /etc/keepalived/scripts/redis_backup.sh
notify_fault /etc/keepalived/scripts/redis_fault.sh
notify_stop /etc/keepalived/scripts/redis_stop.sh
}
四.從redis狀態切換腳本
在/etc/keepalived目錄下建立log和scripts目錄
(1)從redis服務狀態檢測腳本redis_check.sh(136上面內容和它一樣)
#!/bin/bash
###/etc/keepalived/scripts/redis_check.sh
ALIVE=`/opt/redis-3.2.3/src/redis-cli PING` #修改redis-cli的路徑即可,如設置好變量,直接寫"redis-cli"即可
if [ "$ALIVE" == "PONG" ]; then
echo $ALIVE
exit 0
else
echo $ALIVE
exit 1
fi
(2)從 keepalived進入master狀態時的檢測腳本redis_master.sh
#!/bin/bash
###/etc/keepalived/scripts/redis_master.sh
REDISCLI="/opt/redis-3.2.3/src/redis-cli" #修改redis-cli的路徑即可
LOGFILE="/etc/keepalived/log/redis-state.log"
pid=$$
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[backup]" >> $LOGFILE
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[backup] Run 'SLAVEOF 192.168.18.136 6379'" >> $LOGFILE #從redis要寫主redis的IP
$REDISCLI SLAVEOF 192.168.18.136 6379 >> $LOGFILE 2>&1 #從redis要寫主redis的IP
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[backup] wait 10 sec for data sync from old master" >> $LOGFILE
sleep 10
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master] data rsync from old mater ok..." >> $LOGFILE
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master] Run slaveof no one,close master/slave" >> $LOGFILE
$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master] wait other slave connect...." >> $LOGFILE
(3)從keepalived進入backup/stop/fault時的檢測腳本,由於內容都一致,所以只寫出redis_backup.sh
#!/bin/bash
###/etc/keepalived/scripts/redis_backup.sh
REDISCLI="/opt/redis-3.2.3/src/redis-cli"
LOGFILE="/etc/keepalived/log/redis-state.log"
pid=$$
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master] Being slave state..." >> $LOGFILE 2>&1
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master] wait 15 sec for data sync from old master" >> $LOGFILE
sleep 15
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[master] data rsync from old mater ok..." >> $LOGFILE
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[slaver] Run 'SLAVEOF 192.168.18.136 6379'" >> $LOGFILE
$REDISCLI SLAVEOF 192.168.18.136 6379 >> $LOGFILE 2>&1
echo "`date +'%Y-%m-%d:%H:%M:%S'`|$pid|state:[slaver] slave connect to 192.168.18.136 ok..." >> $LOGFILE
五.開始實驗
既然我們設置了nopreempt,那麼在啓動keepalived的時候就有啓動的順序問題了,我們把redis的master和keepalived的master(雖然配置文件中都是backup,但是我們是想讓136這臺做master的,由於在keepalived的master上面設置了nopreempt參數,所以在啓動keepalived服務的時候,一定要先啓動redis master的那臺,因爲在設置了nopreempt了,keepalived在啓動後都是先進入backup狀態,而腳本又設置了進入backup狀態後,會連接新的對方進行數據同步,所以,在啓動keepalived之前還有一個條件就是redis的master和slave中的數據必須一致。這樣先啓動redis的master那臺的keepalived,雖然redis
master會連接到redis slave同步數據,但是兩邊數據在剛開始的時候是一致的,並不會產生什麼問題。
1.模擬一,首先我們把redis按順序啓動,然後查看哨兵以及redis.log是否數據同步。
查看redis日誌,我們發現以及跟137的達成同步了。
我們再把主redis關掉,會看到原來的主已經變成從了,而VIP也已經飄逸過去137身上了。
2.模擬二,把keepalived關掉,redis正常的情況下會發現它也自動切換VIP並把主變成了從。
總結:從以上可以見得,不管是keepalived宕了,還是redis宕了,都會自動去執行腳本並切換他,使得無縫切換,更多的切換時間參數已經超時時間,後續你們自己配一下就好,我就不多說了,其他的現象,你們也可以模擬一下,在實驗的過程中發現有問題的,可以在下方評論,我會回饋你們的。