Redis主從架構(gòu)機(jī)制是什么,考考你對Redis理解深度
Redis主從架構(gòu)
單機(jī)的redis,能夠承載的QPS大概就在上萬到幾萬不等。對于緩存來說,一般都是用來支撐讀高并發(fā)的。因此架構(gòu)做成主從(master-slave)架構(gòu),一主多從,主負(fù)責(zé)寫,并且將數(shù)據(jù)復(fù)制到其它的奴隸節(jié)點(diǎn),從節(jié)點(diǎn)負(fù)責(zé)讀。所有的讀請求全部走從節(jié)點(diǎn)。這樣也可以很輕松實(shí)現(xiàn)水平擴(kuò)容,支撐讀高并發(fā)。

redis replication - >主從架構(gòu) - >讀寫分離 - >水平擴(kuò)容支撐讀高并發(fā)
redis replication的核心機(jī)制
- redis采用異步方式復(fù)制數(shù)據(jù)到slave節(jié)點(diǎn),不過redis2.8開始,slave node會(huì)周期性地確認(rèn)自己每次復(fù)制的數(shù)據(jù)量;
- 一個(gè)主節(jié)點(diǎn)是可以配置多個(gè)slave node的;
- slave node也可以連接其他的slave節(jié)點(diǎn);
- slave node做復(fù)制的時(shí)候,不會(huì)阻塞主節(jié)點(diǎn)的正常工作;
- 奴隸節(jié)點(diǎn)在做復(fù)制的時(shí)候,也不會(huì)阻止對自己的查詢操作,它會(huì)用舊的數(shù)據(jù)集來提供服務(wù);但是復(fù)制完成的時(shí)候,需要?jiǎng)h除舊數(shù)據(jù)集,加載新數(shù)據(jù)集,這個(gè)時(shí)候就會(huì)暫停對外服務(wù)了;
- slave node主要用來進(jìn)行橫向擴(kuò)容,做讀寫分離,擴(kuò)展的slave node可以提高讀的吞吐量。
注意,如果采用了主從架構(gòu),那么建議必須開啟主節(jié)點(diǎn)的持久化,不建議用從節(jié)點(diǎn)作為主節(jié)點(diǎn)的數(shù)據(jù)熱備,因?yàn)槟菢拥脑挘绻汴P(guān)掉master的持久化,可能在主宕機(jī)重啟的時(shí)候數(shù)據(jù)是空的,然后可能一經(jīng)過復(fù)制,slave node的數(shù)據(jù)也丟了。
另外,master的各種備份方案,也需要做。萬一本地的所有文件丟失了,從備份中挑選一份rdb去恢復(fù)master,這樣才能確保啟動(dòng)的時(shí)候,是有數(shù)據(jù)的,即使采用了后續(xù)講解的高可用機(jī)制,slave node可以自動(dòng)接管master node,但也可能sentinel還沒檢測到master failure,master node就自動(dòng)重啟了,還是可能導(dǎo)致上面所有的slave node數(shù)據(jù)被清空。
redis主從復(fù)制的核心原理
當(dāng)啟動(dòng)一個(gè)slave node的時(shí)候,它會(huì)發(fā)送一個(gè)PSYNC命令給主節(jié)點(diǎn)。
如果這是奴隸節(jié)點(diǎn)初次連接到主節(jié)點(diǎn),那么會(huì)觸發(fā)一次full resynchronization全量復(fù)制。此時(shí)主會(huì)啟動(dòng)一個(gè)后臺(tái)線程,開始生成RDB一份快照文件,同時(shí)還會(huì)將從客戶端客戶端新收到的所有寫命令緩存在內(nèi)存中。RDB文件生成完畢后,master會(huì)將這個(gè)RDB發(fā)送給slave,slave會(huì)先寫入本地磁盤,然后再從本地磁盤加載到內(nèi)存中,接著master會(huì)將內(nèi)存中緩存的寫命令發(fā)送到slave,slave也會(huì)同步這些數(shù)據(jù).slave node如果跟主節(jié)點(diǎn)有網(wǎng)絡(luò)故障,斷開了連接,會(huì)自動(dòng)重連,連接之后主節(jié)點(diǎn)僅會(huì)復(fù)制給奴隸部分缺少的數(shù)據(jù)。

主從復(fù)制的斷點(diǎn)續(xù)傳
從redis2.8開始,就支持主從復(fù)制的斷點(diǎn)續(xù)傳,如果主從復(fù)制過程中,網(wǎng)絡(luò)連接斷掉了,那么可以接著上次復(fù)制的地方,繼續(xù)復(fù)制下去,而不是從頭開始復(fù)制一份。
主節(jié)點(diǎn)會(huì)在內(nèi)存中維護(hù)一個(gè)backlog,master和slave都會(huì)保存一個(gè)副本偏移還有一個(gè)主運(yùn)行id,offset就是保存在backlog中的。如果master和slave網(wǎng)絡(luò)連接斷掉了,slave會(huì)讓master從上次replica offset開始繼續(xù)復(fù)制,如果沒有找到對應(yīng)的offset,那么就會(huì)執(zhí)行一次resynchronization。
如果根據(jù)host + ip定位主節(jié)點(diǎn),是不靠譜的,如果主節(jié)點(diǎn)重啟或者數(shù)據(jù)出現(xiàn)了變化,那么slave node應(yīng)該根據(jù)不同的運(yùn)行id區(qū)分。
無磁盤化復(fù)制
master在內(nèi)存中直接創(chuàng)建RDB,然后發(fā)送給slave,不會(huì)在自己本地落地磁盤了。只需要在配置文件中開啟repl-diskless-sync yes即可。
repl-diskless-sync yes#等待5s后再開始復(fù)制,因?yàn)橐雀鄐lave重新連接過來 repl-diskless-sync-delay 5
過期關(guān)鍵處理
slave不會(huì)過期密鑰,只會(huì)等待master過期密鑰。如果master過期了一個(gè)密鑰,或者通過LRU淘汰了一個(gè)密鑰,那么會(huì)模擬一條del命令發(fā)送給slave。
復(fù)制的完整流程
slave node啟動(dòng)時(shí),會(huì)在自己本地保存master node的信息,包括主節(jié)點(diǎn)的host和ip,但是復(fù)制流程沒開始。
slave node內(nèi)部有個(gè)定時(shí)任務(wù),每秒檢查是否有新的主節(jié)點(diǎn)要連接和復(fù)制,如果發(fā)現(xiàn),就跟主節(jié)點(diǎn)建立socket網(wǎng)絡(luò)連接。然后slave節(jié)點(diǎn)發(fā)送ping命令給主節(jié)點(diǎn)。如果master設(shè)置了requirepass,那么slave node必須發(fā)送masterauth的口令過去進(jìn)行認(rèn)證.master node ***次執(zhí)行全量復(fù)制,將所有數(shù)據(jù)發(fā)給slave node。而在后續(xù),master node持續(xù)將寫命令,異步復(fù)制給slave node。

全量復(fù)制
master執(zhí)行bgsave,在本地生成一份rdb快照文件。
主節(jié)點(diǎn)將rdb快照文件發(fā)送給從節(jié)點(diǎn),如果rdb復(fù)制時(shí)間超過60秒(repl-timeout),那么slave節(jié)點(diǎn)就會(huì)認(rèn)為復(fù)制失敗,可以適當(dāng)調(diào)大這個(gè)參數(shù)(對于千兆網(wǎng)卡的機(jī)器,一般每秒傳輸100MB,6G文件,很可能超過60s)
主節(jié)點(diǎn)在生成rdb時(shí),會(huì)將所有新的寫命令緩存在內(nèi)存中,在從節(jié)點(diǎn)保存了rdb之后,再將新的寫命令復(fù)制給從節(jié)點(diǎn)。
如果在復(fù)制期間,內(nèi)存緩沖區(qū)持續(xù)消耗超過64MB,或者一次性超過256MB,那么停止復(fù)制,復(fù)制失敗。
client-output-buffer-limit slave 256MB 64MB 60
slave node接收到rdb之后,清空自己的舊數(shù)據(jù),然后重新加載rdb到自己的內(nèi)存中,同時(shí)基于舊的數(shù)據(jù)版本對外提供服務(wù)。
如果slave node開啟了AOF,那么會(huì)立即執(zhí)行BGREWRITEAOF,重寫AOF。
增量復(fù)制
如果全量復(fù)制過程中,master-slave網(wǎng)絡(luò)連接斷掉,那么奴隸重新連接master時(shí),會(huì)觸發(fā)增量復(fù)制。
master直接從自己的backlog中獲取部分丟失的數(shù)據(jù),發(fā)送給slave node,默認(rèn)backlog就是1MB。
msater就是根據(jù)slave發(fā)送的psync中的offset來自backlog中獲取數(shù)據(jù)的。
心跳
主從節(jié)點(diǎn)互相都會(huì)發(fā)送心跳信息。
master默認(rèn)每隔10秒發(fā)送一次heartbeat,slave node每隔1秒發(fā)送一個(gè)heartbeat。
異步復(fù)制
master每次接收到寫命令之后,先在內(nèi)部寫入數(shù)據(jù),然后異步發(fā)送給從屬節(jié)點(diǎn)。
redis如何才能做到高可用
如果系統(tǒng)在365天內(nèi),有99.99%的時(shí)間,都是可以嘩嘩對外提供服務(wù)的,那么就說系統(tǒng)是高可用的。
一個(gè)奴隸掛掉了,是不會(huì)影響可用性的,還有其它的奴隸在提供相同數(shù)據(jù)下的相同的對外的查詢服務(wù)。
但是,如果主節(jié)點(diǎn)死掉了,會(huì)怎么樣?沒法寫數(shù)據(jù)了,寫緩存的時(shí)候,全部失效了.slave node還有什么用呢,沒有master給它們復(fù)制數(shù)據(jù)了,系統(tǒng)相當(dāng)于不可用了。
redis的高可用架構(gòu),叫做failover 故障轉(zhuǎn)移,也可以叫做主備切換。
主節(jié)點(diǎn)在故障時(shí),自動(dòng)檢測,并且將某個(gè)從節(jié)點(diǎn)自動(dòng)切換位主節(jié)點(diǎn)的過程,叫做主備切換。這個(gè)過程,實(shí)現(xiàn)了redis的主從架構(gòu)下的高可用。
后面會(huì)詳細(xì)說明redis 基于哨兵的高可用性。