1. 程式人生 > >redis+sentinel+keepalived 高可用,可實現多臺並單點訪問

redis+sentinel+keepalived 高可用,可實現多臺並單點訪問

       之前有寫過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的達成同步了。


再檢視哨兵日誌,發現136已經變成137的主了。


我們再把主redis關掉,會看到原來的主已經變成從了,而VIP也已經飄逸過去137身上了。


2.模擬二,把keepalived關掉,redis正常的情況下會發現它也自動切換VIP並把主變成了從。


         總結:從以上可以見得,不管是keepalived宕了,還是redis宕了,都會自動去執行指令碼並切換他,使得無縫切換,更多的切換時間引數已經超時時間,後續你們自己配一下就好,我就不多說了,其他的現象,你們也可以模擬一下,在實驗的過程中發現有問題的,可以在下方評論,我會回饋你們的。