Redis做爲內存數據庫,須要具有高可用的特色,否則若是服務器宕機,還在內存裏的數據就會丟失。咱們最經常使用的高可用方法就是搭建集羣,master機器掛了,可讓slave機器頂上,繼續提供服務。可是Redis集羣是不會自動進行主從切換的,也就是說,若是主節點很是不爭氣的在凌晨3點掛了,那麼運維同窗就要立刻起牀,把從節點改爲主節點,這樣的操做是很是繁瑣低效的。爲此,Redis官方提供了一種解決方案:Redis Sentinelpython
Redis Sentinel集羣一般由3到5個節點組成,若是個別節點掛了,集羣還能夠正常運做。它負責監控Redis集羣的健康狀況。若是主節點掛掉,Sentinel集羣會經過投票選擇一個新的主節點。當原來的主節點恢復時,它會被當作新的主節點的從節點從新加入Redis集羣。redis
Sentinel集羣經過指定的配置文件發現master,對其進行監控,而且會發送info指令獲取master的從節點信息。Sentinel集羣中的節點經過向其監控的主從節點發送hello信息(包含Sentinel自己的ip、端口和id等內容)來向其餘Sentinel宣告本身的存在。數據庫
Sentinel集羣經過訂閱鏈接來接收其餘Sentinel的hello信息。bash
Sentinel集羣經過ping命令來檢查監控的實例狀態,若是在指定時間內沒有返回,則認爲該實例下線。服務器
Sentinel觸發failover主從切換後,並不會立刻進行,只有指定(quorum)Sentinel受權後,master節點被標記爲ODOWN狀態。這時才真正開始投票選擇新的master。運維
Sentinel選擇新的master的原則是:首先判斷優先級,選擇優先級較小的;若是優先級相同,查看複製下標,選擇複製數據較多的;若是複製下標也相同,就選擇進程ID較小的。socket
Sentinel被受權後,它將會得到宕掉的master的一份最新配置版本號(config-epoch),當failover執行結束之後,這個版本號將會被用於最新的配置,經過廣播形式通知其它Sentinel,其它的Sentinel則更新對應master的配置。測試
咱們以Python爲例,簡單說明一下在客戶端如何使用Sentinelui
from redis.sentinel import Sentinel
if __name__ == '__main__':
sentinel = Sentinel(['localhost', 26379], socket_timeout=0.1)
print(sentinel.discover_master('mymaster'))
print(sentinel.discover_slaves('mymaster'))
master = sentinel.master_for('mymaster', socket_timeout=0.1)
slave = sentinel.slave_for('mymaster', socket_timeout=0.1)
master.set('follow', 'Jackeyzhe2018')
follow = slave.get('follow')
print(follow)
複製代碼
master_for和slave_for方法會從鏈接池中拿出一個鏈接來使用,若是從地址有多個,則會採用輪詢的方法。spa
當redis發生了主從切換時,客戶端如何知道地址已經變動了呢?咱們從redis-py的源碼裏找一找答案。
能夠看到,redis在建立一個新的鏈接時,會調用get_master_address方法來獲取主節點地址。get_master_address方法中,客戶端先查詢主節點地址,而後與內存中的地址進行比較。若是不一致,則會斷開鏈接,而後使用新的地址從新進行鏈接。
若是主節點沒有掛,而Sentinel主動進行了主從切換,對於這種狀況redis-py也作了處理。就是捕獲一個ReadOnlyError的異常,而後斷開鏈接,後續指令都須要從新進行鏈接了。固然,若是沒有修改性指令,那麼鏈接就不會切換,不過數據也不會被破壞,因此影響不大。
關於Sentinel的工做原理和使用方法咱們已經有了大概的認識,爲了加深理解,咱們來本身動手搭建一套Sentinel集羣。
首先搭建咱們我須要的redis集羣環境
安裝好redis後,將redis目錄下的配置文件redis.conf複製3份。分別命名爲redis6379.conf,redis6380.conf,redis6381.conf。
在redis6381.conf文件中修改如下幾項
bind 127.0.0.1
port 6381
logfile "6381.log"
dbfilename "dump-6381.rdb"
複製代碼
在redis6379.conf中修改
bind 127.0.0.1
port 6379
logfile "6379.log"
dbfilename "dump-6379.rdb"
slaveof 127.0.0.1 6381
複製代碼
redis6380.conf的修改參照redis6379.conf。修改完成後,分別啓動三個實例。就搭建好了咱們想要的redis主從環境了。
咱們鏈接上master節點,能夠看到它的主從配置信息
接着,咱們來配置Sentinel集羣。這裏咱們一樣配置三個實例。複製3份sentinel.conf文件,分別命名爲sentinel-26379.conf,sentinel-26380.conf和sentinel-26381.conf。
sentinel-26379.conf文件中編輯如下內容
port 26379
daemonize yes
logfile "26379.log"
dir /home/xxx/redis/data
sentinel monitor mymaster 127.0.0.1 6381 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
複製代碼
sentinel-26380.conf和sentinel-26381.conf的內容與上述相似。配置好後,咱們使用命令redis-sentinel來啓動3個sentinel實例。
此時,咱們用redis-cli命令鏈接26379的實例,查看sentinel的信息。
發現它已經開始監控咱們的3個redis節點了。這時咱們的整個集羣就部署好了,接下來測試一下。
kill掉master節點,查看sentinel的日誌,會發現sentinel已經按照咱們前面說的步驟選擇了新的master。
此時再來看sentinel信息。
此時,6380已經成了新的master。
恭喜你,之後都不須要在凌晨起牀切換Redis主從實例了。