keepalived+redis 高可用redis主從解決方案

來源:互聯網
上載者:User

標籤:

背景介紹:

目前,Redis還沒有一個類似於MySQL Proxy或Oracle RAC的官方HA方案。
#Redis 2.8版開始正式提供名為Sentinel的主從切換方案(後面附上,未測試)

因此,如何在出現故障時自動轉移是一個需要解決的問題。

通過對網上一些資料的搜尋,有建議採用HAProxy或Keepalived來實現的,事實上如果是做Failover而非負載平衡的話,Keepalived的效率肯定是超過HAProxy的,所以我決定採用Keepalived的方案。

環境介紹:
Master: 192.168.0.100
Slave: 192.168.0.101
Virtural IP Address (VIP): 192.168.0.200

設計思路:

當 Master 與 Slave 均運作正常時, Master負責服務,Slave負責Standby;
當 Master 掛掉,Slave 正常時, Slave接管服務,同時關閉主從複製功能;
當 Master 恢複正常,則從Slave同步資料,同步資料之後關閉主從複製功能,恢複Master身份,於此同時Slave等待Master同步資料完成之後,恢複Slave身份。
然後依次迴圈。

需要注意的是,這樣做需要在Master與Slave上都開啟本地化策略,否則在互相自動切換的過程中,未開啟本地化的一方會將另一方的資料清空,造成資料完全丟失。

下面,是具體的實施步驟:

在Master和Slave上安裝Keepalived

$ yum install keepalived

預設安裝完成keepalived有預設的設定檔,因此我們重寫覆蓋它:

首先,在Master上建立如下設定檔
$ vim /etc/keepalived/keepalived.conf

! Configuration File for keepalived
global_defs {
   router_id redis100
}
vrrp_script chk_redis 

     script "/etc/keepalived/scripts/redis_check.sh 127.0.0.1 6379" 
     interval 2 
     timeout 2
     fall 3
}
vrrp_instance redis {
     state MASTER # master set to SLAVE also
     interface eth0  
     virtual_router_id 50 
     priority  150       
     nopreempt # no seize,must add
     advert_int 1
authentication {   #all node must same
         auth_type PASS
         auth_pass 1111
    }
    virtual_ipaddress {  
192.168.0.200/24
    }
    track_script { 
         chk_redis 
    } 
     notify_master "/etc/keepalived/scripts/redis_master.sh 127.0.0.1 192.168.0.101 6379"
     notify_backup "/etc/keepalived/scripts/redis_backup.sh 127.0.0.1 192.168.0.101 6379"
     notify_fault /etc/keepalived/scripts/redis_fault.sh 
     notify_stop /etc/keepalived/scripts/redis_stop.sh 
}

然後,在Slave上建立如下設定檔:

! Configuration File for keepalived

global_defs {
   router_id redis101
}
vrrp_script chk_redis 

     script "/etc/keepalived/scripts/redis_check.sh 127.0.0.1 6379" 
     interval 2
     timeout 2
     fall 3
}
vrrp_instance redis {
    state BACKUP   
    interface eth0   
    virtual_router_id 50  
    priority  100       
    advert_int 1
authentication {   #all node must same
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress { 
    192.168.0.200/24
    }
    track_script { 
         chk_redis 
    } 
    notify_master "/etc/keepalived/scripts/redis_master.sh 127.0.0.1 192.168.0.100 6379"
    notify_backup "/etc/keepalived/scripts/redis_backup.sh 127.0.0.1 192.168.0.100 6379"
    notify_fault /etc/keepalived/scripts/redis_fault.sh 
    notify_stop /etc/keepalived/scripts/redis_stop.sh 
}

在Master和Slave上建立監控Redis的指令碼
$ mkdir /etc/keepalived/scripts
$ vim /etc/keepalived/scripts/redis_check.sh

#!/bin/bash 
ALIVE=`/usr/redis/redis-cli -h $1 -p $2 PING` 
LOGFILE="/var/log/keepalived-redis-check.log" 
echo "[CHECK]" >> $LOGFILE
date >> $LOGFILE
if [ $ALIVE == "PONG" ]; then :
   echo "Success: redis-cli -h $1 -p $2 PING $ALIVE" >> $LOGFILE 2>&1
    exit 0 
else 
    echo "Failed:redis-cli -h $1 -p $2 PING $ALIVE " >> $LOGFILE 2>&1
    exit 1 
fi 

編寫以下負責運作的關鍵指令碼:
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

因為Keepalived在轉換狀態時會依照狀態來呼叫:
當進入Master狀態時會呼叫notify_master
當進入Backup狀態時會呼叫notify_backup
當發現異常情況時進入Fault狀態呼叫notify_fault
當Keepalived程式終止時則呼叫notify_stop

首先,在Redis Master上建立notity_master與notify_backup指令碼:
$ vim /etc/keepalived/scripts/redis_master.sh

#!/bin/bash 
REDISCLI="/usr/redis/redis-cli -h $1 -p $3" 
LOGFILE="/var/log/keepalived-redis-state.log" 
echo "[master]" >> $LOGFILE 
date >> $LOGFILE 
echo "Being master...." >> $LOGFILE 2>&1  
echo "Run MASTER cmd ..." >> $LOGFILE 2>&1
$REDISCLI SLAVEOF $2 $3 >> $LOGFILE  
sleep 10 #delay 10 s wait data async cancel sync
echo "Run SLAVEOF NO ONE cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1

 

 

$ sudo vim /etc/keepalived/scripts/redis_backup.sh

#!/bin/bash 
REDISCLI="/usr/redis/redis-cli" 
LOGFILE="/var/log/keepalived-redis-state.log" 
echo "[backup]" >> $LOGFILE 
date >> $LOGFILE 
echo "Run SLAVEOF cmd ..." >> $LOGFILE 
$REDISCLI SLAVEOF $2 $3 >> $LOGFILE 2>&1 
# echo "Being slave...." >> $LOGFILE 2>&1 
sleep 15 #delay 15 s wait data sync exchange role 


接著,在Redis Slave上建立notity_master與notify_backup指令碼:

$ vim /etc/keepalived/scripts/redis_master.sh

#!/bin/bash 
REDISCLI="/usr/redis/redis-cli -h $1 -p $3" 
LOGFILE="/var/log/keepalived-redis-state.log" 
echo "[master]" >> $LOGFILE 
date >> $LOGFILE 
echo "Being master...." >> $LOGFILE 2>&1 
echo "Run SLAVEOF cmd ... " >> $LOGFILE 
$REDISCLI SLAVEOF $2 $3 >> $LOGFILE  2>&1
#echo "SLAVEOF $2 cmd can‘t excute ... " >> $LOGFILE 
sleep 10 ##delay 15 s wait data sync exchange role
echo "Run SLAVEOF NO ONE cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1 


$ vim /etc/keepalived/scripts/redis_backup.sh

#!/bin/bash 
REDISCLI="/usr/redis/redis-cli" 
LOGFILE="/var/log/keepalived-redis-state.log" 
echo "[BACKUP]" >> $LOGFILE 
date >> $LOGFILE 
echo "Being slave...." >> $LOGFILE 2>&1 
echo "Run SLAVEOF cmd ..." >> $LOGFILE 2>&1
$REDISCLI SLAVEOF $2 $3 >> $LOGFILE  
sleep 100 #delay 10 s wait data async cancel sync 
exit(0)


然後在Master與Slave建立如下相同的指令碼:
$ vim /etc/keepalived/scripts/redis_fault.sh

#!/bin/bash 
LOGFILE=/var/log/keepalived-redis-state.log 
echo "[fault]" >> $LOGFILE
date >> $LOGFILE 

$ sudo vim /etc/keepalived/scripts/redis_stop.sh

#!/bin/bash 
LOGFILE=/var/log/keepalived-redis-state.log 
echo "[stop]" >> $LOGFILE 
date >> $LOGFILE 

給指令碼都加上可執行許可權:

(這點很重要,最開始由於這不沒做,運行後一直報錯 "VRRP_Instance(redis) Now in FAULT state")

$ sudo chmod +x /etc/keepalived/scripts/*.sh

指令碼建立完成以後,我們開始按照如下流程進行測試
1.啟動Master上的Redis
$ /etc/init.d/redis start

2.啟動Slave上的Redis
$ /etc/init.d/redis start

3.啟動Master上的Keepalived
$ /etc/init.d/keepalived start

4.啟動Slave上的Keepalived
$ /etc/init.d/keepalived start


5.嘗試通過VIP串連Redis:
$ redis-cli -h 10.6.1.200 INFO

串連成功,Slave也串連上來了。
role:master
slave0:10.6.1.144,6379,online

6.嘗試插入一些資料:
$ redis-cli -h 10.6.1.200 SET Hello Redis
OK

從VIP讀取資料
$ redis-cli -h 10.6.1.200 GET Hello
"Redis"

從Master讀取資料
$ redis-cli -h 10.6.1.143 GET Hello
"Redis"

從Slave讀取資料
$ redis-cli -h 10.6.1.144 GET Hello
"Redis"


下面,類比故障產生:
將Master上的Redis停了
$ service redis_6379 stop

查看Master上的Keepalived日誌
$ tailf /var/log/keepalived-redis-state.log
[fault]
Thu Sep 27 08:29:01 CST 2012

同時Slave上的日誌顯示:
$ tailf /var/log/keepalived-redis-state.log
[master]
Fri Sep 28 14:14:09 CST 2012
Being master....
Run SLAVEOF cmd ...
OK
Run SLAVEOF NO ONE cmd ...
OK

然後我們可以發現,Slave已經接管服務,並且擔任Master的角色了。
$ redis-cli -h 192.168.0.200 INFO

role:master

然後我們恢複Master的Redis進程
$ service redis_6379 start

查看Master上的Keepalived日誌
$ tailf /var/log/keepalived-redis-state.log
[master]
Thu Sep 27 08:31:33 CST 2012
Being master....
Run SLAVEOF cmd ...
OK
Run SLAVEOF NO ONE cmd ...
OK

同時Slave上的日誌顯示:
$ tailf /var/log/keepalived-redis-state.log
[backup]
Fri Sep 28 14:16:37 CST 2012
Being slave....
Run SLAVEOF cmd ...
OK

可以發現目前的Master已經再次恢複了Master的角色,故障切換以及自動回復都成功了。

主從用到的指令碼及keepalived.conf 可以從這下載 http://download.csdn.net/detail/huwei2003/8252221

注意事項:主從的redis都要開啟本地備份

 

附:

Redis Sentinel的主從切換方案

 

Redis 2.8版開始正式提供名為Sentinel的主從切換方案,Sentinel用於管理多個Redis伺服器執行個體,主要負責三個方面的任務:

    1. 監控(Monitoring): Sentinel 會不斷地檢查你的主伺服器和從伺服器是否運作正常。
    2. 提醒(Notification): 當被監控的某個 Redis 伺服器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程式發送通知。
    3. 自動故障遷移(Automatic failover): 當一個主伺服器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主伺服器的其中一個從伺服器升級為新的主伺服器, 並讓失效主伺服器的其他從伺服器改為複製新的主伺服器; 當用戶端試圖串連失效的主伺服器時, 叢集也會向用戶端返回新主伺服器的地址, 使得叢集可以使用新主伺服器代替失效伺服器。

Redis Sentinel 是一個分布式系統, 你可以在一個架構中運行多個 Sentinel 進程(progress), 這些進程使用流言協議(gossip protocols)來接收關於主伺服器是否下線的資訊, 並使用投票協議(agreement protocols)來決定是否執行自動故障遷移, 以及選擇哪個從伺服器作為新的主伺服器。

啟動Sentinel

使用--sentinel參數啟動,並必須指定一個對應的設定檔,系統會使用設定檔來儲存 Sentinel 的目前狀態, 並在 Sentinel 重啟時通過載入設定檔來進行狀態還原。

    redis-server /path/to/sentinel.conf --sentinel

使用TCP連接埠26379,可以使用redis-cli或其他任何用戶端與其通訊。

如果啟動 Sentinel 時沒有指定相應的設定檔, 或者指定的設定檔不可寫(not writable), 那麼 Sentinel 會拒絕啟動。

配置Sentinel

以下是一段設定檔的樣本:

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1

sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5

    第一行配置指示 Sentinel 去監視一個名為 mymaster 的主伺服器, 這個主伺服器的 IP 位址為 127.0.0.1 , 連接埠號碼為 6379 , 而將這個主伺服器判斷為失效至少需要 2 個 Sentinel 同意 (只要同意 Sentinel 的數量不達標,自動故障遷移就不會執行)。
    不過需要注意的是,無論你設定要多少個 Sentinel 同意才能判斷一個伺服器失效,一個 Sentinel 都需要獲得系統中多數(majority) Sentinel 的支援,才能發起一次自動故障遷移,並預留一個給定的配置紀元 (Configuration Epoch ,一個配置紀元就是一個新主伺服器配置的版本號碼)。也就是說,如果只有少數(minority)Sentinel 進程正常運作的情況下,是不能執行自動故障遷移的。

    down-after-milliseconds 選項指定了 Sentinel 認為伺服器已經斷線所需的毫秒數(判定為主觀下線SDOWN)。
    parallel-syncs 選項指定了在執行容錯移轉時, 最多可以有多少個從伺服器同時對新的主伺服器進行同步, 這個數字越小, 完成容錯移轉所需的時間就越長,但越大就意味著越多的從伺服器因為複製而不可用。可以通過將這個值設為 1 來保證每次只有一個從伺服器處於不能處理命令請求的狀態。

主觀下線和客觀下線

    1. 主觀下線(Subjectively Down, 簡稱 SDOWN)指的是單個 Sentinel 執行個體對伺服器做出的下線判斷。
    2. 客觀下線(Objectively Down, 簡稱 ODOWN)指的是多個 Sentinel 執行個體在對同一個伺服器做出 SDOWN 判斷, 並且通過 SENTINEL is-master-down-by-addr 命令互相交流之後, 得出的伺服器下線判斷。

客觀下線條件只適用於主伺服器: 對於任何其他類型的 Redis 執行個體, Sentinel 在將它們判斷為下線前不需要進行協商, 所以從伺服器或者其他 Sentinel 永遠不會達到客觀下線條件。
只要一個 Sentinel 發現某個主伺服器進入了客觀下線狀態, 這個 Sentinel 就可能會被其他 Sentinel 推選出, 並對失效的主伺服器執行自動故障遷移操作。

每個Sentinel執行個體都執行的定時任務

    1. 每個 Sentinel 以每秒鐘一次的頻率向它所知的主伺服器、從伺服器以及其他 Sentinel 執行個體發送一個 PING 命令。
    2. 如果一個執行個體(instance)距離最後一次有效回複 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 那麼這個執行個體會被 Sentinel 標記為主觀下線。 一個有效回複可以是: +PONG 、 -LOADING 或者 -MASTERDOWN 。
    3. 如果一個主伺服器被標記為主觀下線, 那麼正在監視這個主伺服器的所有 Sentinel 要以每秒一次的頻率確認主伺服器的確進入了主觀下線狀態。
    4. 如果一個主伺服器被標記為主觀下線, 並且有足夠數量的 Sentinel (至少要達到設定檔指定的數量)在指定的時間範圍內同意這一判斷, 那麼這個主伺服器被標記為客觀下線。
    5. 在一般情況下, 每個 Sentinel 會以每 10 秒一次的頻率向它已知的所有主伺服器和從伺服器發送 INFO 命令。 當一個主伺服器被 Sentinel 標記為客觀下線時, Sentinel 向下線主伺服器的所有從伺服器發送 INFO 命令的頻率會從 10 秒一次改為每秒一次。
    6. 當沒有足夠數量的 Sentinel 同意主伺服器已經下線, 主伺服器的客觀下線狀態就會被移除。 當主伺服器重新向 Sentinel 的 PING 命令返回有效回複時, 主伺服器的主管下線狀態就會被移除。

Sentinel API

有兩種方式可以與Sentinel進行通訊:指令、發布與訂閱。

    Sentinel命令

       PING :返回 PONG 。
       SENTINEL masters :列出所有被監視的主伺服器,以及這些主伺服器的目前狀態;
       SENTINEL slaves <master name> :列出給定主伺服器的所有從伺服器,以及這些從伺服器的目前狀態;
       SENTINEL get-master-addr-by-name <master name> : 返回給定名字的主伺服器的 IP 位址和連接埠號碼。 如果這個主伺服器正在執行容錯移轉操作, 或者針對這個主伺服器的容錯移轉操作已經完成, 那麼這個                     命令返回新的主伺服器的 IP 位址和連接埠號碼;
       SENTINEL reset <pattern> : 重設所有名字和給定模式 pattern 相匹配的主伺服器。 pattern 參數是一個 Glob 風格的模式。 重設操作清楚主伺服器目前的所有狀態, 包括正在執行中的容錯移轉, 並移除目前已經發現和關聯的, 主伺服器的所有從伺服器和 Sentinel ;
       SENTINEL failover <master name> : 當主伺服器失效時, 在不詢問其他 Sentinel 意見的情況下, 強制開始一次自動故障遷移。

用戶端可以通過SENTINEL get-master-addr-by-name <master name>擷取當前的主伺服器IP地址和連接埠號碼,以及SENTINEL slaves <master name>擷取所有的Slaves資訊

    發布與訂閱資訊

    用戶端可以將 Sentinel 看作是一個只提供了訂閱功能的 Redis 伺服器: 你不可以使用 PUBLISH 命令向這個伺服器發送資訊, 但你可以用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 通過訂閱給定的頻道來擷取相應的事件提醒。
   一個頻道能夠接收和這個頻道的名字相同的事件。 比如說, 名為 +sdown 的頻道就可以接收所有執行個體進入主觀下線(SDOWN)狀態的事件。
   通過執行 PSUBSCRIBE * 命令可以接收所有事件資訊。

        +switch-master <master name> <oldip> <oldport> <newip> <newport> :配置變更,主伺服器的 IP 和地址已經改變。 這是絕大多數外部使用者都關心的資訊。

    可以看出,我們使用Sentinel命令和發布訂閱兩種機制就能很好的實現和用戶端的整合整合:
    使用get-master-addr-by-name和slaves指令可以擷取當前的Master和Slaves的地址和資訊;而當發生容錯移轉時,即Master發生切換,可以通過訂閱的+switch-master事件獲得最新的Master資訊。

    *PS:更多Sentinel的可訂閱事件參見官方文檔。

sentinel.conf中的notification-script

    在sentinel.conf中可以配置多個sentinel notification-script <master name> <shell script-path>, 如sentinel notification-script mymaster ./check.sh

    這個是在群集failover時會觸發執行指定的指令碼。指令碼的執行結果若為1,即稍後重試(最大重試次數為10);若為2,則執行結束。並且指令碼最大執行時間為60秒,逾時會被終止執行。

    PS:目前會存在該指令碼被執行多次的問題,尋找資料有人解釋是:
        指令碼分為兩個層級, SENTINEL_LEADER 和 SENTINEL_OBSERVER ,前者僅由領頭 Sentinel 執行(一個 Sentinel),而後者由監視同一個 master 的所有 Sentinel 執行(多個 Sentinel)。

keepalived+redis 高可用redis主從解決方案

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.