一、主從架構(gòu)
主從架構(gòu)就是一個master節(jié)點,兩個slave節(jié)點。
1.1 Redis主從數(shù)據(jù)如何同步?
Redis主從架構(gòu)同步數(shù)據(jù)分為兩種情況:1、全量同步數(shù)據(jù) 2、部分?jǐn)?shù)據(jù)同步。
1.2 全量同步數(shù)據(jù)
1.當(dāng)slave和master建立長鏈接后,slave就會發(fā)送psync命令要求同步數(shù)據(jù)
2.master接收到psync命令后,就會先執(zhí)行bgsave,將內(nèi)存的數(shù)據(jù)生成rdb快照
3.在master生成rdb快照期間,如果還有命令要執(zhí)行,會緩存到repl buffer當(dāng)中
4.master將生成的rdb數(shù)據(jù)發(fā)送給slave
5.slave接收到rdb快照后,會清除本地的舊數(shù)據(jù),然后再將rdb加載到內(nèi)存中
6.master將緩存的buffer數(shù)據(jù)發(fā)送給slave
7.slave接收到緩存的buffer數(shù)據(jù),會重做本地數(shù)據(jù)
8.master通過長鏈接發(fā)送命令,實現(xiàn)主從數(shù)據(jù)一致性

1.3 部分?jǐn)?shù)據(jù)同步
主節(jié)點和從節(jié)點都會維護一個復(fù)制偏移量——offset,如果從節(jié)點完整復(fù)制了主節(jié)點的數(shù)據(jù),那么主從節(jié)點的復(fù)制偏移量就是相同的。
1.master會緩存近期的一些寫操作命令,緩存在repl buffer中,默認(rèn)大小是1mb。
2.slave節(jié)點斷開重連后建立socket長鏈接
3.slave發(fā)送psync(offset)命令要求同步數(shù)據(jù)
4.master的buffer中如果有offset,那么將會把offset之后的所有數(shù)據(jù)都發(fā)送給slave,否則將全量同步數(shù)據(jù)
5.master通過socket長鏈接發(fā)送數(shù)據(jù),實現(xiàn)主從數(shù)據(jù)一致性

主從復(fù)制風(fēng)暴:
當(dāng)一個主節(jié)點有多個從節(jié)點時,在同一時刻多個從節(jié)點都要同步數(shù)據(jù),那么主節(jié)點在這一刻的壓力會非常大,可能導(dǎo)致主節(jié)點出現(xiàn)問題——這個就是主從復(fù)制風(fēng)暴。
為了解決這個問題,可以將主從的架構(gòu)設(shè)置成梯形的,也就是從節(jié)點也可以是主節(jié)點。

二、哨兵架構(gòu)
在主從架構(gòu)中,雖然能解決一定的并發(fā)和讀寫分離,但是整個主從架構(gòu)不是高可用的。一旦主節(jié)點下線后,只能人為介入切換主節(jié)點,為了解決這個問題,sentinel(哨兵)架構(gòu)就應(yīng)運而生。
哨兵是特殊的redis服務(wù),不提供讀寫服務(wù),主要就是用來監(jiān)控redis節(jié)點。
2.1 sentinel會與主從服務(wù)器建立連接
sentinel一旦和主從服務(wù)器建立連接后,就能感知到哪個節(jié)點是master。當(dāng)client第一次連接時,sentinel會返回主節(jié)點的信息給client,后續(xù)client就直接和master進行通信。
2.2 sentinel感知主節(jié)點下線
sentinel會定期發(fā)送PING命令給其它節(jié)點,根據(jù)節(jié)點是否回復(fù)PONG命令來判斷哪些節(jié)點已下線。一旦sentinel發(fā)現(xiàn)master下線,就會選舉新的master,然后推送給client。
2.3 sentinel選舉流程
1、當(dāng)某個sentinel發(fā)現(xiàn)master下線后,會將自己設(shè)置成leader
2、當(dāng)該sentienl得到了半數(shù)以上節(jié)點的同意,就會成為sentinel leader
3、sentinel leader開始選取一個存活的slave節(jié)點作為新的master,然后推送給client

三、集群架構(gòu)
3.1 集群的數(shù)據(jù)存儲
redis cluster是通過邏輯槽位來劃分?jǐn)?shù)據(jù),redis cluster總共將所有數(shù)據(jù)劃分為16384個slot(槽位),然后每個節(jié)點負(fù)責(zé)一部分槽位的數(shù)據(jù)進行存儲。
3.2 計算key落入哪個槽位
通過對key使用CRC16進行hash運算,得到一個hash值,然后再使用hash值和16384進行與運算,得到最終的槽位信息。
計算公式:Hash_slot = CRC16(key) & 16384。
3.3 跳轉(zhuǎn)重定位
當(dāng)服務(wù)端發(fā)生槽位信息變動時,客戶端可能沒有感知到最新的槽位信息,讓然使用舊的槽位向服務(wù)器發(fā)送寫命令。
當(dāng)服務(wù)器發(fā)現(xiàn)該槽位不屬于我這個節(jié)點管理時,會給客戶端響應(yīng)一個重定位的信息,并附帶該槽位對應(yīng)的節(jié)點信息。客戶端接收到新的槽位信息后,會更新本地緩存的槽位信息,然后再次發(fā)送指令給服務(wù)器。
3.4 集群的選舉原理
當(dāng)某個slave發(fā)現(xiàn)它的master下線后,會對外廣播failover信息,然后開始競選master,當(dāng)某個slave節(jié)點擁有半數(shù)以上的投票結(jié)果時,這個slave節(jié)點就會成為新的master。
選舉流程:
1.slave發(fā)現(xiàn)master的狀態(tài)變成fail
2.slave會對外廣播failover信息,然后集群的選舉周期+1
3.其它節(jié)點接收到廣播后,只有master才會響應(yīng),并且返回ack
4.當(dāng)該slave節(jié)點擁有半數(shù)以上的ack時,就成為新的master
當(dāng)slave發(fā)現(xiàn)master下線后,不是立刻發(fā)起選舉的,而是有一個delay time,這個delay time就是防止多個slave節(jié)點競選master時票數(shù)一致,導(dǎo)致選舉失敗。
3.5 集群腦裂問題
當(dāng)集群中出現(xiàn)網(wǎng)絡(luò)分區(qū)問題時,有多個master對外提供服務(wù),當(dāng)網(wǎng)絡(luò)分區(qū)恢復(fù)時,其中一個master將清空數(shù)據(jù),變成salve。這樣就會導(dǎo)致部分?jǐn)?shù)據(jù)丟失,而redis提供了一個配置項,可以降低數(shù)據(jù)丟失的風(fēng)險——min-replicas-to-write 1。

四、總結(jié)
主從架構(gòu):能解決讀寫分離問題,但是只有一個主節(jié)點,抗不了很高的并發(fā),主從切換也不支持。
哨兵架構(gòu):可以自動切換主從節(jié)點,但是仍然只有一個主節(jié)點,只解決了高可用。
集群架構(gòu):解決了高可用、高并發(fā)問題,還引入了邏輯槽位,將數(shù)據(jù)進行分片存儲,降低了單個小集群的讀寫壓力,還支持水平擴展,整體提升了redis的性能。