漫畫(huà)解讀redis集群|哨兵|腦裂

哨兵

還是拿現(xiàn)實(shí)生活舉例,假設(shè)某小公司暫存資料的柜子,有多個(gè)格子,柜子還有一個(gè)專門(mén)的管理員,他的工作就是按公司員工的命令在某個(gè)格子(key)存資料(value),取資料(value)。

管理員+柜子就相當(dāng)于redis,員工向柜子管理員發(fā)命令存取資料,所以每個(gè)員工相當(dāng)一個(gè)個(gè)客戶端。

redis

但公司的管理員經(jīng)常跑肚拉稀上廁所,導(dǎo)致無(wú)法提供服務(wù)

redis服務(wù)可能因?yàn)榫W(wǎng)絡(luò)問(wèn)題,服務(wù)器問(wèn)題導(dǎo)致宕機(jī)

為了應(yīng)對(duì)這種問(wèn)題,公司采取主從方案,給主管理員配置多個(gè)從管理員,原管理員升職為主管理員,他們的職責(zé)是這樣的,主管理員提供存取服務(wù)和原來(lái)一樣,每個(gè)從管理員也掌管一個(gè)新柜子,并且主柜子里有什么他們就復(fù)制一份存入自己的柜子,和主管理員的資料實(shí)時(shí)同步,而且可以分擔(dān)一部分的取資料任務(wù)。

這就是redis的主從架構(gòu),一個(gè)主節(jié)點(diǎn)配幾個(gè)個(gè)從節(jié)點(diǎn),從節(jié)點(diǎn)實(shí)時(shí)同步主節(jié)點(diǎn)的數(shù)據(jù),主節(jié)點(diǎn)可以承接讀寫(xiě)命令,從節(jié)點(diǎn)可以承接讀命令,至于如何主從如何同步數(shù)據(jù)移步上一篇文章

主從架構(gòu)

這樣做確實(shí)可以主管理員分擔(dān)壓力,但是當(dāng)主管理員上廁所時(shí)候還是無(wú)法提供存資料的服務(wù),因?yàn)?code>從管理員只承接取資料任務(wù)不能存資料。

單純的主從架構(gòu),主節(jié)點(diǎn)掛了,redis就不能set了

所以需要一個(gè)方案,能在主管理員不在崗的時(shí)候,選一個(gè)從管理員升級(jí)為主管理員。為此公司組建了個(gè)監(jiān)控團(tuán)隊(duì),他們負(fù)責(zé)監(jiān)控所有柜子管理員,如果主管理員不在崗,他們負(fù)責(zé)選出一個(gè)新主管理員,該方案起名叫哨兵方案

哨兵模式

這個(gè)監(jiān)控團(tuán)隊(duì)就是哨兵集群,哨兵集群由多個(gè)哨兵服務(wù)組成,sentinel哨兵是特殊的redis服務(wù),不提供讀寫(xiě)服務(wù),主要用來(lái)監(jiān)控redis實(shí)例節(jié)點(diǎn),主節(jié)點(diǎn)掛了選舉出一個(gè)新的主節(jié)點(diǎn)并告知客戶端。

redis哨兵架構(gòu)

由于本文主要討論集群,哨兵就簡(jiǎn)單介紹一下。

集群

公司的這個(gè)哨兵方案有個(gè)大問(wèn)題,就是不管多少個(gè)從管理員,負(fù)責(zé)存資料的只有一個(gè)主管理員,如果公司越來(lái)越大,存資料人多了,他會(huì)應(yīng)付不過(guò)來(lái),而且資料越來(lái)越多,柜子不斷變大,會(huì)導(dǎo)致從管理員復(fù)制資料越來(lái)越慢。

Redis哨兵架構(gòu)中只有主節(jié)點(diǎn)負(fù)責(zé)寫(xiě)命令,如果并發(fā)量很大,執(zhí)行等待時(shí)間會(huì)變長(zhǎng),而且redis內(nèi)存不宜過(guò)大(盡量10G以下),要不增加主從復(fù)制和持久化的壓力,兩種情況都會(huì)導(dǎo)致redis可用性就會(huì)降低,所以并發(fā)量特大或需緩存數(shù)據(jù)特別多情況下哨兵架構(gòu)表現(xiàn)就很一般。

公司越來(lái)越大,人和資料越來(lái)越多,所以提出一個(gè)新方案:集群方案。
方案其實(shí)很簡(jiǎn)單,人多了,多上幾個(gè)柜子分開(kāi)存不就就可以了嗎,具體方案如下:
多增幾組柜子管理員,分別存放不類型的資料,由于每個(gè)柜子存放的資料不同,所以為了防止管理員跑肚拉稀,還是留著主從管理員這套體系,一個(gè)主從體系取名叫一個(gè)柜子小組,分A、B、C組,多個(gè)柜子小組共同提供存取資料服務(wù)。

集群

redis常用的集群架構(gòu)就是多個(gè)主從組合成一個(gè)大集群,這樣解決了高并發(fā)時(shí)的反應(yīng)速度問(wèn)題,把壓力分散給不同節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)也不用存儲(chǔ)太多數(shù)據(jù),例如需要存30G數(shù)據(jù),三個(gè)節(jié)點(diǎn)每個(gè)節(jié)點(diǎn)存10G就可以了。


高可用集群模式

槽位定位算法

問(wèn)題來(lái)了,這么多組柜子+管理員,怎么分配工作,即什么樣的文件存在什么柜子里。
解決思路很簡(jiǎn)單,分類就可以了,比如公司當(dāng)前就三組柜A,B,C,那么就給公司所有資料分為A,B,C類,A類存A柜、B類存B柜、C類存C柜即可。每個(gè)員工手上都有一個(gè)類型和柜子的對(duì)照?qǐng)D,避免存錯(cuò)柜子。
但是這樣會(huì)有問(wèn)題,比如公司又壯大了,增加了個(gè)D組柜,那D組柜放什么資料?沒(méi)資料可放了...,加了也白加,或者給資料重新分類,但是太麻煩。
于是公司預(yù)估了一下按發(fā)展未來(lái)可能最多會(huì)上16384個(gè)柜,那么就給資料分16384類。
分類方法比如可以按資料的編號(hào)(假設(shè)純粹數(shù)字而且很大,是16384的好幾倍)對(duì)16384取模,得到的范圍0-16383的資料類型值。
這樣就實(shí)現(xiàn)了對(duì)所有資料分16384類,然后給每個(gè)柜子小組分配多個(gè)類型的任務(wù),比如類A組0-4999類,B組5000-9999類,C組10000-16383類,將來(lái)來(lái)了個(gè)D組,從這些組取一部分類區(qū)間給D,D組柜子就實(shí)際派上用場(chǎng)了。

定位

Redis Cluster采用槽位定位算法,將所有數(shù)據(jù)劃分為 16384 個(gè)slots(槽位),每個(gè)節(jié)點(diǎn)負(fù)責(zé)其中一部分槽位。槽位的信息存儲(chǔ)于每個(gè)節(jié)點(diǎn)中。
Cluster默認(rèn)會(huì)對(duì)key值使用crc16算法進(jìn)行hash得到一個(gè)整數(shù)值,然后用這個(gè)整數(shù)值對(duì)16384進(jìn)行取模來(lái)得到具體槽位。16384個(gè)槽位可以看出集群的節(jié)點(diǎn)最多也就1萬(wàn)多個(gè),再多可能就分不到任務(wù)了,官方推薦是1000以下。

每個(gè)公司員工首先要知道各柜子小組負(fù)責(zé)的資料類型分布,簡(jiǎn)稱分布圖,才能知道要去哪存,這個(gè)分布圖每個(gè)柜子小組都有一份,一般員工得到后會(huì)用一張紙記錄一下,省著總?cè)?wèn)。

分布圖

客戶端要訪問(wèn)redis集群首先要拿到槽位的信息,然后才能根據(jù)key的運(yùn)算知道具體要訪問(wèn)的節(jié)點(diǎn),這個(gè)槽位的信息每個(gè)節(jié)點(diǎn)都持有,可以從任何一個(gè)節(jié)點(diǎn)獲取,獲取之后一般要暫存一份,避免每次都重新獲取。

如果分布圖過(guò)期了、錯(cuò)了,導(dǎo)致定位錯(cuò)了柜子小組柜子小組管理員會(huì)告訴員工正確的柜子是哪個(gè),比較聰明的員工出現(xiàn)這種問(wèn)題,會(huì)知道自己的分布圖不準(zhǔn)確,會(huì)重新要一份更新自己的分部圖。

當(dāng)redis客戶端向一個(gè)錯(cuò)誤的節(jié)點(diǎn)發(fā)出了指令,該節(jié)點(diǎn)會(huì)發(fā)現(xiàn)指令的 key 所在的槽位并不歸自己管理,這時(shí)它會(huì)向客戶端發(fā)送一個(gè)特殊的跳轉(zhuǎn)指令攜帶目標(biāo)操作的節(jié)點(diǎn)地址,告訴客戶端去連這個(gè)節(jié)點(diǎn)去獲取數(shù)據(jù)


重定向

此時(shí)客戶端合理的操作會(huì)重新獲取一下槽位的信息

jedis|spring

通過(guò)上面的描述會(huì)發(fā)現(xiàn),需要員工做的事太多了:1.記下分布圖,2.計(jì)算文件類型值, 3.根據(jù)分布圖和計(jì)算的文件類型值,去找對(duì)應(yīng)的 柜子小組存取資料,4.如果發(fā)現(xiàn)找錯(cuò)了柜子小組,重新獲取分布圖,重新定位柜子小組。

程序員連接redis集群需要負(fù)責(zé)如下邏輯:

  • 緩存槽位分布圖
  • 計(jì)算槽位
  • 根據(jù)分布圖定位節(jié)點(diǎn),發(fā)送請(qǐng)求
  • 出現(xiàn)錯(cuò)誤更新槽位分布圖,重新定位節(jié)點(diǎn)發(fā)請(qǐng)求

寫(xiě)個(gè)代碼太累了。。。
好在這些或都被第三方工具封裝好了,比如jedis和spring,他們內(nèi)部屏蔽掉了這些事情,所以我們代碼只負(fù)責(zé)存取即可,和操作單機(jī)redis一樣一樣的。

gossip

柜子小組之間,需要互相通信,每個(gè)管理員彼此保留聯(lián)系方式,并長(zhǎng)期保持通話,可以想象為大家建立了一個(gè)群聊,彼此通信,因?yàn)闆](méi)有一個(gè)統(tǒng)一的指揮者,也不像哨兵方案那樣有監(jiān)控者,所以需要各小組互相協(xié)調(diào)。

redis集群的多個(gè)節(jié)點(diǎn)都會(huì)互相通信,這樣才能感知彼此,同步槽位信息,重定向等功能,有點(diǎn)像去中心化的區(qū)塊鏈,通信協(xié)議gossip有點(diǎn)復(fù)雜,有空單獨(dú)研究。

選舉

柜子小組中,每個(gè)主管理員+柜子(簡(jiǎn)稱主柜)都配一兩個(gè)從管理員+柜子(簡(jiǎn)稱從柜),保留主從體系,這樣當(dāng)主柜不在崗了,會(huì)有一個(gè)從柜被重新競(jìng)選為主柜,以保證所有柜子小組都可用。

競(jìng)選

集群方案中,從柜提供的讀功能就比較雞肋了,所以集群方案中從柜只負(fù)責(zé)復(fù)制數(shù)據(jù)和隨時(shí)準(zhǔn)備頂替主柜
上面介紹過(guò)哨兵方案中由監(jiān)控人員來(lái)選舉出新的主,但新的集群方案并不存在這個(gè)角色,那是如何進(jìn)行選舉的吶?方案如下:
假如A組主柜管理員不在了,那本組的兩個(gè)從柜管理員開(kāi)始競(jìng)爭(zhēng)上崗,他們分別聯(lián)系其他組的主管理員,其他組的主管理員會(huì)給第一個(gè)聯(lián)系上他的競(jìng)選者投一票,如果競(jìng)選者收到的投票超過(guò)小組數(shù)的一半,則成功當(dāng)選。如果倆人平分秋色,或者都沒(méi)達(dá)到要求,那么重新選舉,直到選出為止。
選舉

為了避免選的次數(shù)太多,公司規(guī)定每個(gè)競(jìng)選者進(jìn)行選舉前需要等一會(huì),具體等待的時(shí)間跟復(fù)制的資料新舊有關(guān),資料越新代表他的復(fù)制工作做的越好,更能還原前任主柜的資料,那么對(duì)應(yīng)的竟選擇等待的時(shí)間就短,競(jìng)選成功的概率就大。
但是又出問(wèn)題了,如果倆競(jìng)選者資料一樣新,可能又會(huì)出現(xiàn)多次選舉失敗浪費(fèi)時(shí)間,所以在看資料新舊的基礎(chǔ)上,再加一個(gè)隨機(jī)抽數(shù)環(huán)節(jié),比如弄個(gè)抽獎(jiǎng)箱,里面放多個(gè)數(shù)字,抽中幾就等幾秒,這樣大大減少了選舉的次數(shù)。

所以還原度越高的從柜不一定當(dāng)選,但被選中的幾率相對(duì)更大。

Redis Cluster 中,當(dāng)slave發(fā)現(xiàn)自己的master變?yōu)镕AIL狀態(tài)時(shí),便嘗試進(jìn)行選舉,以期成為新的master。其過(guò)程如下:

  • slave廣播競(jìng)選信息
  • 其它master收到信息,回應(yīng)ack,每個(gè)主節(jié)點(diǎn)每輪選舉只回應(yīng)一次ack
  • slave收集master返回的ack
  • slave收到超過(guò)半數(shù)master的ack后變成新master
  • slave廣播pong消息通知其他集群節(jié)點(diǎn)競(jìng)選成功。

slave并不是在master一進(jìn)入 FAIL 狀態(tài)就馬上嘗試發(fā)起選舉,而是有一定延遲。
延遲計(jì)算公式:

 DELAY = 500ms + random(0 ~ 500ms) + slave_rank* 1000ms
  • slave_rank
    slave已復(fù)制的數(shù)據(jù)越新,slave_rank值越小,延遲越低
  • random(0 ~ 500ms)
    加一個(gè)隨機(jī)數(shù),避免多slave的slave_rank相同重復(fù)選舉

小補(bǔ)充

1.為什么集群主節(jié)點(diǎn)至少三個(gè)?
因?yàn)樾枰霐?shù)以上票數(shù)才能競(jìng)選成功,集群的半數(shù)機(jī)制,所以集群至少三個(gè)主節(jié)點(diǎn),因?yàn)槿绻袀z個(gè)主節(jié)點(diǎn),一個(gè)掛了,選舉最多只能收一票,不大于主節(jié)點(diǎn)數(shù)的一半,所以永遠(yuǎn)不會(huì)競(jìng)選成功。
2.集群是否完整才能對(duì)外提供服務(wù)?
加入一個(gè)主節(jié)點(diǎn)掛了,且沒(méi)有從節(jié)點(diǎn)可替換,那么這組的槽位數(shù)據(jù)訪問(wèn)不了了,但其他的主節(jié)點(diǎn)原則應(yīng)該也可以繼續(xù)訪問(wèn),那么具體可不可以訪問(wèn)吶?答案是:可配,配置項(xiàng)是cluster-require-full-coverage

腦裂

回到例子,還是A,B,C三組,所有組的所有成員彼此通信,有一天出現(xiàn)了問(wèn)題,A組的主管理員由于一些原因,聯(lián)系不上其他人了,其他人也都發(fā)現(xiàn)A主柜聯(lián)系不上了,于是從新從A組中重新選出了一個(gè)主柜
這樣一來(lái)有些知道變更的員工就去新主柜存取資料,但還有一些不知道變更的員工還會(huì)取舊主柜存取資料,導(dǎo)致出現(xiàn)了兩個(gè)主柜在這期間各存各的。

腦裂

如圖,綠色藍(lán)色是兩個(gè)不同的辦公區(qū),中間有個(gè)大鐵門(mén)突然被鎖住了,導(dǎo)致彼此不能通信,A組的原主聯(lián)系不上其他管理員,但是還得繼續(xù)給綠區(qū)員工提供服務(wù)。其它管理員也聯(lián)系不上A組原主,只能推選一個(gè)新的主柜,給黃區(qū)員工提供服務(wù),這樣同一邏輯組A實(shí)際上就共同存在了兩個(gè)主。
過(guò)了一段時(shí)間,門(mén)打開(kāi),彼此互相可以通信了,原主柜發(fā)現(xiàn)集群有新主柜了。。。沒(méi)辦法,只能自己充當(dāng)從柜,清空自己的資料去同步復(fù)制新主柜的資料,這樣就導(dǎo)致隔離這段期間原主柜新增的資料消失了。
腦裂恢復(fù)丟失數(shù)據(jù)

redis集群會(huì)有腦裂問(wèn)題,網(wǎng)絡(luò)分區(qū)導(dǎo)致腦裂后多個(gè)主節(jié)點(diǎn)對(duì)外提供寫(xiě)服務(wù),一旦網(wǎng)絡(luò)分區(qū)恢復(fù),會(huì)將其中一個(gè)主節(jié)點(diǎn)變?yōu)閺墓?jié)點(diǎn),這時(shí)會(huì)有大量數(shù)據(jù)丟失。

為了應(yīng)對(duì)這種情況,公司針對(duì)一主雙從提出了一個(gè)方案,每次主管理員存資料時(shí),至少一個(gè)從管理員完成同步復(fù)制才算存儲(chǔ)成功,否則告訴員工失敗,這樣就可以避免腦裂問(wèn)題:
當(dāng)出現(xiàn)某主柜和其他所有管理員通信斷了的情況,主柜由于聯(lián)系不到任何從柜無(wú)法提供存資料服務(wù)。
如果主柜攜帶某個(gè)從柜一起和其它管理員斷了通信,由于兩個(gè)從柜一個(gè)能找到主,一個(gè)不能找到主,不符合半數(shù)機(jī)制,不能發(fā)起重新選舉。
對(duì)應(yīng)的如果5個(gè)從柜可以讓其中3個(gè)確認(rèn)才算成功,以此類推。

redis規(guī)避腦裂的方法:可以在redis配置里加上參數(shù)(這種方法不可能百分百避免數(shù)據(jù)丟失,參考集群leader選舉機(jī)制):

min-replicas-to-write 1  //寫(xiě)數(shù)據(jù)成功最少同步的slave數(shù)量,這個(gè)數(shù)量可以模仿大于半數(shù)機(jī)制配置,比如集群總共三個(gè)節(jié)點(diǎn)可以配置1,加上leader就是2,超過(guò)了半數(shù)

注意:這個(gè)配置在一定程度上會(huì)影響集群的可用性,比如slave要是少于1個(gè),這個(gè)集群就算leader正常也不能提供服務(wù)了,需要具體場(chǎng)景權(quán)衡選擇。
over~畫(huà)圖不易,如果對(duì)你有幫助,給個(gè)贊吧!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容