我們?cè)陧?xiàng)目中使用Redis,肯定不會(huì)是單點(diǎn)部署Redis服務(wù)的。因?yàn)椋瑔吸c(diǎn)部署一旦宕機(jī),就不可用了。為了實(shí)現(xiàn)高可用,通常的做法是,將數(shù)據(jù)庫復(fù)制多個(gè)副本以部署在不同的服務(wù)器上,其中一臺(tái)掛了也可以繼續(xù)提供服務(wù)。Redis 實(shí)現(xiàn)高可用有三種部署模式:主從模式,哨兵模式,集群模式。
主從模式中Redis部署了多臺(tái)機(jī)器,有負(fù)責(zé)讀寫操作主節(jié)點(diǎn)和只負(fù)責(zé)讀操作從節(jié)點(diǎn),從節(jié)點(diǎn)的數(shù)據(jù)來自主節(jié)點(diǎn),實(shí)現(xiàn)原理就是主從復(fù)制機(jī)制。主從復(fù)制包括全量復(fù)制,增量復(fù)制兩種。一般當(dāng)slave第一次啟動(dòng)連接master,或者認(rèn)為是第一次連接,就采用全量復(fù)制,全量復(fù)制流程如下:
1.slave發(fā)送sync命令到master。
2.master接收到SYNC命令后,執(zhí)行bgsave命令,生成RDB全量文件。
3.master使用緩沖區(qū),記錄RDB快照生成期間的所有寫命令。
4.master執(zhí)行完bgsave后,向所有slave發(fā)送RDB快照文件。
5.slave收到RDB快照文件后,載入、解析收到的快照。
6.master使用緩沖區(qū),記錄RDB同步期間生成的所有寫的命令。
7.master快照發(fā)送完畢后,開始向slave發(fā)送緩沖區(qū)中的寫命令;
8.salve接受命令請(qǐng)求,并執(zhí)行來自master緩沖區(qū)的寫命令
redis2.8版本之后,已經(jīng)使用psync來替代sync,因?yàn)閟ync命令非常消耗系統(tǒng)資源,psync的效率更高。
slave與master全量同步之后,master上的數(shù)據(jù),如果再次發(fā)生更新,就會(huì)觸發(fā)增量復(fù)制。
當(dāng)master節(jié)點(diǎn)發(fā)生數(shù)據(jù)增減時(shí),就會(huì)觸發(fā)replicationFeedSalves()函數(shù),接下來在 Master節(jié)點(diǎn)上調(diào)用的每一個(gè)命令會(huì)使用replicationFeedSlaves()來同步到Slave節(jié)點(diǎn)。執(zhí)行此函數(shù)之前呢,master節(jié)點(diǎn)會(huì)判斷用戶執(zhí)行的命令是否有數(shù)據(jù)更新,如果有數(shù)據(jù)更新的話,并且slave節(jié)點(diǎn)不為空,就會(huì)執(zhí)行此函數(shù)。這個(gè)函數(shù)作用就是:把用戶執(zhí)行的命令發(fā)送到所有的slave節(jié)點(diǎn),讓slave節(jié)點(diǎn)執(zhí)行。流程如下:
Redis的哨兵(sentinel) 系統(tǒng)用于管理多個(gè) Redis 服務(wù)器,該系統(tǒng)執(zhí)行以下三個(gè)任務(wù):
1)監(jiān)控(Monitoring): 哨兵(sentinel) 會(huì)不斷地檢查你的Master和Slave是否運(yùn)作正常。
2)提醒(Notification):當(dāng)被監(jiān)控的某個(gè) Redis出現(xiàn)問題時(shí), 哨兵(sentinel) 可以通過 API 向管理員或者其他應(yīng)用程序發(fā)送通知。
3)自動(dòng)故障遷移(Automatic failover):當(dāng)一個(gè)Master不能正常工作時(shí),哨兵(sentinel) 會(huì)開始一次自動(dòng)故障遷移操作,它會(huì)將失效Master的其中一個(gè)Slave升級(jí)為新的Master, 并讓失效Master的其他Slave改為復(fù)制新的Master; 當(dāng)客戶端試圖連接失效的Master時(shí),集群也會(huì)向客戶端返回新Master的地址,使得集群可以使用Master代替失效Master。
監(jiān)控主數(shù)據(jù)庫和從數(shù)據(jù)庫是否正常運(yùn)行。
主數(shù)據(jù)庫出現(xiàn)故障時(shí),可以自動(dòng)將從數(shù)據(jù)庫轉(zhuǎn)換為主數(shù)據(jù)庫,實(shí)現(xiàn)自動(dòng)切換。
當(dāng)主節(jié)點(diǎn)出現(xiàn)故障時(shí),由Redis Sentinel自動(dòng)完成故障發(fā)現(xiàn)和轉(zhuǎn)移,并通知應(yīng)用方,實(shí)現(xiàn)高可用性。
其實(shí)整個(gè)過程只需要一個(gè)哨兵節(jié)點(diǎn)來完成,首先使用Raft算法(選舉算法)實(shí)現(xiàn)選舉機(jī)制,選出一個(gè)哨兵節(jié)點(diǎn)來完成轉(zhuǎn)移和通知
1)哨兵集群至少要 3 個(gè)節(jié)點(diǎn),來確保自己的健壯性
2)redis主從 + sentinel的架構(gòu),是不會(huì)保證數(shù)據(jù)的零丟失的,它是為了保證redis集群的高可用.
會(huì)有,主要考慮下面兩種情況。
1)主從異步復(fù)制導(dǎo)致的數(shù)據(jù)丟失:redis master 和slave 數(shù)據(jù)復(fù)制是異步的,這樣就有可能會(huì)出現(xiàn)部分?jǐn)?shù)據(jù)還沒有復(fù)制到slave中,master就掛掉了,那么這部分的數(shù)據(jù)就會(huì)丟失了
2)腦裂導(dǎo)致的數(shù)據(jù)丟失:腦裂其實(shí)就是網(wǎng)絡(luò)分區(qū)導(dǎo)致的現(xiàn)象,比如,我們的master機(jī)器網(wǎng)絡(luò)突然不正常了發(fā)生了網(wǎng)絡(luò)分區(qū),和其他的slave機(jī)器不能正常通信了,其實(shí)master并沒有掛還活著好好的呢,但是哨兵可不是吃閑飯的啊,它會(huì)認(rèn)為master掛掉了啊,那么問題來了,client可能還在繼續(xù)寫master的呀,還沒來得及更新到新的master呢,那這部分?jǐn)?shù)據(jù)就會(huì)丟失。
如果一個(gè)master被認(rèn)為宕機(jī)了,而且majority多數(shù)哨兵都允許了主備切換,那么某個(gè)哨兵就會(huì)執(zhí)行主備切換操作,此時(shí)首先要選舉一個(gè)slave來,主要通過下面幾個(gè)步驟
1)slave跟master斷開連接的時(shí)長(斷開時(shí)間越短優(yōu)先級(jí)越高)
2)slave優(yōu)先級(jí)(在配置文件中的配置,slave priority越低,優(yōu)先級(jí)就越高。)
3)復(fù)制offset(哪個(gè)slave復(fù)制了越多的數(shù)據(jù),offset越靠后,優(yōu)先級(jí)就越高。)
4)run id(如果上面兩個(gè)條件都相同,那么選擇一個(gè)run id比較小的那個(gè)slave)
redis從3.0開始支持集群功能。redis集群采用無中心節(jié)點(diǎn)方式實(shí)現(xiàn),無需proxy代理,客戶端直接與redis集群的每個(gè)節(jié)點(diǎn)連接,根據(jù)同樣的hash算法計(jì)算出key對(duì)應(yīng)的slot,然后直接在slot對(duì)應(yīng)的redis節(jié)點(diǎn)上執(zhí)行命令。在redis看來,響應(yīng)時(shí)間是最苛刻的條件,增加一層帶來的開銷是redis不能接受的。因此,redis實(shí)現(xiàn)了客戶端對(duì)節(jié)點(diǎn)的直接訪問,為了去中心化,節(jié)點(diǎn)之間通過gossip協(xié)議交換互相的狀態(tài),以及探測新加入的節(jié)點(diǎn)信息。redis集群支持動(dòng)態(tài)加入節(jié)點(diǎn),動(dòng)態(tài)遷移slot,以及自動(dòng)故障轉(zhuǎn)移。