0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Redis的主從、哨兵、Redis Cluster集群

jf_ro2CN3Fa ? 來(lái)源:芋道源碼 ? 2023-06-12 14:58 ? 次閱讀

前言

今天跟小伙伴們一起學(xué)習(xí)Redis的主從、哨兵、Redis Cluster集群。

Redis主從

Redis哨兵

Redis Cluster集群

基于 Spring Boot + MyBatis Plus + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

項(xiàng)目地址:https://github.com/YunaiV/ruoyi-vue-pro

視頻教程:https://doc.iocoder.cn/video/

1. Redis 主從

面試官經(jīng)常會(huì)問(wèn)到Redis的高可用。Redis高可用回答包括兩個(gè)層面,一個(gè)就是數(shù)據(jù)不能丟失,或者說(shuō)盡量減少丟失 ;另外一個(gè)就是保證Redis服務(wù)不中斷 。

對(duì)于盡量減少數(shù)據(jù)丟失,可以通過(guò)AOF和RDB保證。

對(duì)于保證服務(wù)不中斷的話,Redis就不能單點(diǎn)部署,這時(shí)候我們先看下Redis主從。

1.1 Redsi主從概念

Redis主從模式,就是部署多臺(tái)Redis服務(wù)器,有主庫(kù)和從庫(kù),它們之間通過(guò)主從復(fù)制,以保證數(shù)據(jù)副本的一致。

主從庫(kù)之間采用的是讀寫(xiě)分離 的方式,其中主庫(kù)負(fù)責(zé)讀操作和寫(xiě)操作,從庫(kù)則負(fù)責(zé)讀操作。

如果Redis主庫(kù)掛了,切換其中的從庫(kù)成為主庫(kù)。

1.2 Redis 主從同步過(guò)程

5e6863bc-08c1-11ee-962d-dac502259ad0.png

Redis主從同步包括三個(gè)階段。

第一階段:主從庫(kù)間建立連接、協(xié)商同步。

從庫(kù)向主庫(kù)發(fā)送psync 命令,告訴它要進(jìn)行數(shù)據(jù)同步。

主庫(kù)收到 psync 命令后,響應(yīng)FULLRESYNC命令(它表示第一次復(fù)制采用的是全量復(fù)制 ),并帶上主庫(kù)runID和主庫(kù)目前的復(fù)制進(jìn)度offset。

第二階段:主庫(kù)把數(shù)據(jù)同步到從庫(kù),從庫(kù)收到數(shù)據(jù)后,完成本地加載。

主庫(kù)執(zhí)行bgsave命令,生成RDB文件,接著將文件發(fā)給從庫(kù)。從庫(kù)接收到RDB 文件后,會(huì)先清空當(dāng)前數(shù)據(jù)庫(kù),然后加載 RDB 文件。

主庫(kù)把數(shù)據(jù)同步到從庫(kù)的過(guò)程中,新來(lái)的寫(xiě)操作,會(huì)記錄到replication buffer。

第三階段,主庫(kù)把新寫(xiě)的命令,發(fā)送到從庫(kù)。

主庫(kù)完成RDB發(fā)送后,會(huì)把replication buffer中的修改操作發(fā)給從庫(kù),從庫(kù)再重新執(zhí)行這些操作。這樣主從庫(kù)就實(shí)現(xiàn)同步啦。

1.3 Redis主從的一些注意點(diǎn)

1.3.1 主從數(shù)據(jù)不一致

因?yàn)橹鲝膹?fù)制是異步進(jìn)行的,如果從庫(kù)滯后執(zhí)行,則會(huì)導(dǎo)致主從數(shù)據(jù)不一致 。

主從數(shù)據(jù)不一致一般有兩個(gè)原因:

主從庫(kù)網(wǎng)路延遲。

從庫(kù)收到了主從命令,但是它正在執(zhí)行阻塞性的命令(如hgetall等)。

如何解決主從數(shù)據(jù)不一致問(wèn)題呢?

可以換更好的硬件配置,保證網(wǎng)絡(luò)暢通。

監(jiān)控主從庫(kù)間的復(fù)制進(jìn)度

1.3.2 讀取過(guò)期數(shù)據(jù)

Redis刪除數(shù)據(jù)有這幾種策略:

惰性刪除:只有當(dāng)訪問(wèn)一個(gè)key時(shí),才會(huì)判斷該key是否已過(guò)期,過(guò)期則清除。

定期刪除:每隔一定的時(shí)間,會(huì)掃描一定數(shù)量的數(shù)據(jù)庫(kù)的expires字典中一定數(shù)量的key,并清除其中已過(guò)期的key。

主動(dòng)刪除:當(dāng)前已用內(nèi)存超過(guò)最大限定時(shí),觸發(fā)主動(dòng)清理策略。

如果使用Redis版本低于3.2,讀從庫(kù)時(shí),并不會(huì)判斷數(shù)據(jù)是否過(guò)期,而是會(huì)返回過(guò)期數(shù)據(jù) 。而3.2 版本后,Redis做了改進(jìn),如果讀到的數(shù)據(jù)已經(jīng)過(guò)期了,從庫(kù)不會(huì)刪除,卻會(huì)返回空值,避免了客戶端讀到過(guò)期數(shù)據(jù) 。

因此,在主從Redis模式下,盡量使用 Redis 3.2 以上的版本。

1.3.3 一主多從,全量復(fù)制時(shí)主庫(kù)壓力問(wèn)題

如果是一主多從模式,從庫(kù)很多的時(shí)候,如果每個(gè)從庫(kù)都要和主庫(kù)進(jìn)行全量復(fù)制的話,主庫(kù)的壓力是很大的。因?yàn)橹鲙?kù)fork進(jìn)程生成RDB,這個(gè)fork的過(guò)程是會(huì)阻塞主線程處理正常請(qǐng)求的。同時(shí),傳輸大的RDB文件也會(huì)占用主庫(kù)的網(wǎng)絡(luò)寬帶。

可以使用主-從-從 模式解決。什么是主從從模式呢?其實(shí)就是部署主從集群時(shí),選擇硬件網(wǎng)絡(luò)配置比較好的一個(gè)從庫(kù),讓它跟部分從庫(kù)再建立主從 關(guān)系。如圖:

5ea58cb0-08c1-11ee-962d-dac502259ad0.png

1.3.4 主從網(wǎng)絡(luò)斷了怎么辦呢?

主從庫(kù)完成了全量復(fù)制后,它們之間會(huì)維護(hù)一個(gè)網(wǎng)絡(luò)長(zhǎng)連接,用于主庫(kù)后續(xù)收到寫(xiě)命令傳輸?shù)綇膸?kù),它可以避免頻繁建立連接的開(kāi)銷。但是,如果網(wǎng)絡(luò)斷開(kāi)重連后,是否還需要進(jìn)行一次全量復(fù)制呢?

如果是Redis 2.8之前,從庫(kù)和主庫(kù)重連后,確實(shí)會(huì)再進(jìn)行一次全量復(fù)制,但是這樣開(kāi)銷就很大。而Redis 2.8之后做了優(yōu)化,重連后采用增量復(fù)制方式,即把主從庫(kù)網(wǎng)絡(luò)斷連期間主庫(kù)收到的寫(xiě)命令,同步給從庫(kù)。

主從庫(kù)重連后,就是利用repl_backlog_buffer 實(shí)現(xiàn)增量復(fù)制。

當(dāng)主從庫(kù)斷開(kāi)連接后,主庫(kù)會(huì)把斷連期間收到的寫(xiě)操作命令,寫(xiě)入replication buffer ,同時(shí)也會(huì)把這些操作命令寫(xiě)入repl_backlog_buffer 這個(gè)緩沖區(qū)。repl_backlog_buffer是一個(gè)環(huán)形緩沖區(qū),主庫(kù)會(huì)記錄自己寫(xiě)到的位置,從庫(kù)則會(huì)記錄自己已經(jīng)讀到的位置。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

項(xiàng)目地址:https://github.com/YunaiV/yudao-cloud

視頻教程:https://doc.iocoder.cn/video/

2. Redis哨兵

主從模式中,一旦主節(jié)點(diǎn)由于故障不能提供服務(wù),需要人工將從節(jié)點(diǎn)晉升為主節(jié)點(diǎn),同時(shí)還要通知應(yīng)用方更新主節(jié)點(diǎn)地址。顯然,多數(shù)業(yè)務(wù)場(chǎng)景都不能接受這種故障處理方式。Redis從2.8開(kāi)始正式提供了Redis哨兵機(jī)制 來(lái)解決這個(gè)問(wèn)題。

哨兵作用

哨兵模式簡(jiǎn)介

哨兵如何判定主庫(kù)下線

哨兵模式如何工作

哨兵是如何選主的

由哪個(gè)哨兵執(zhí)行主從切換呢?

哨兵下的故障轉(zhuǎn)移

2.1 哨兵作用

哨兵其實(shí)是一個(gè)運(yùn)行在特殊模式下的Redis進(jìn)程。它有三個(gè)作用,分別是:監(jiān)控、自動(dòng)選主切換(簡(jiǎn)稱選主)、通知 。

哨兵進(jìn)程在運(yùn)行期間,監(jiān)視所有的Redis主節(jié)點(diǎn)和從節(jié)點(diǎn)。它通過(guò)周期性給主從庫(kù) 發(fā)送PING命令,檢測(cè)主從庫(kù)是否掛了。如果從庫(kù) 沒(méi)有在規(guī)定時(shí)間內(nèi)響應(yīng)哨兵的PING命令,哨兵就會(huì)把它標(biāo)記為下線狀態(tài) ;如果主庫(kù)沒(méi)有在規(guī)定時(shí)間內(nèi)響應(yīng)哨兵的PING命令,哨兵則會(huì)判定主庫(kù)下線,然后開(kāi)始切換到選主 任務(wù)。

所謂選主 ,其實(shí)就是從多個(gè)從庫(kù)中,按照一定規(guī)則,選出一個(gè)當(dāng)做主庫(kù)。至于通知 呢,就是選出主庫(kù)后,哨兵把新主庫(kù)的連接信息發(fā)給其他從庫(kù),讓它們和新主庫(kù)建立主從關(guān)系。同時(shí),哨兵也會(huì)把新主庫(kù)的連接信息通知給客戶端,讓它們把請(qǐng)求操作發(fā)到新主庫(kù)上。

2.2 哨兵模式

因?yàn)镽edis哨兵也是一個(gè)Redis進(jìn)程,如果它自己掛了呢,那是不是就起不了監(jiān)控的作用啦。我們一起來(lái)看下Redis哨兵模式

哨兵模式,就是由一個(gè)或多個(gè)哨兵實(shí)例組成的哨兵系統(tǒng),它可以監(jiān)視所有的Redis主節(jié)點(diǎn)和從節(jié)點(diǎn),并在被監(jiān)視的主節(jié)點(diǎn)進(jìn)入下線狀態(tài)時(shí),自動(dòng)將下線主服務(wù)器屬下的某個(gè)從節(jié)點(diǎn)升級(jí)為新的主節(jié)點(diǎn)。,一個(gè)哨兵進(jìn)程對(duì)Redis節(jié)點(diǎn)進(jìn)行監(jiān)控,就可能會(huì)出現(xiàn)問(wèn)題(單點(diǎn)問(wèn)題)。因此,一般使用多個(gè)哨兵來(lái)進(jìn)行監(jiān)控Redis節(jié)點(diǎn),并且各個(gè)哨兵之間還會(huì)進(jìn)行監(jiān)控。

5eb9f48e-08c1-11ee-962d-dac502259ad0.png

其實(shí)哨兵之間是通過(guò)發(fā)布訂閱機(jī)制 組成集群的,同時(shí),哨兵又通過(guò)INFO命令,獲得了從庫(kù)連接信息,也能和從庫(kù)建立連接,從而進(jìn)行監(jiān)控。

2.3 哨兵如何判定主庫(kù)下線

哨兵是如何判斷主庫(kù)是否下線的呢?我們先來(lái)了解兩個(gè)基礎(chǔ)概念哈:主觀下線和客觀下線 。

哨兵進(jìn)程向主庫(kù)、從庫(kù) 發(fā)送PING命令,如果主庫(kù)或者從庫(kù)沒(méi)有在規(guī)定的時(shí)間內(nèi)響應(yīng)PING命令,哨兵就把它標(biāo)記為主觀下線

如果是主庫(kù)被標(biāo)記為主觀下線 ,則正在監(jiān)視這個(gè)主庫(kù)的所有哨兵 要以每秒一次的頻率,以確認(rèn)主庫(kù)是否真的進(jìn)入了主觀下線 。當(dāng)有多數(shù) 的哨兵(一般少數(shù)服從多數(shù),由 Redis 管理員自行設(shè)定的一個(gè)值 )在指定的時(shí)間范圍內(nèi)確認(rèn)主庫(kù)的確進(jìn)入了主觀下線狀態(tài),則主庫(kù)會(huì)被標(biāo)記為客觀下線 。這樣做的目的就是避免對(duì)主庫(kù)的誤判 ,以減少?zèng)]有必要的主從切換,減少不必要的開(kāi)銷。

假設(shè)我們有N個(gè)哨兵實(shí)例,如果有N/2+1個(gè)實(shí)例判斷主庫(kù)主觀下線 ,此時(shí)就可以把節(jié)點(diǎn)標(biāo)記為客觀下線 ,就可以做主從切換了。

2.4 哨兵的工作模式

每個(gè)哨兵以每秒鐘一次的頻率向它所知的主庫(kù)、從庫(kù)以及其他哨兵實(shí)例發(fā)送一個(gè)PING命令。

如果一個(gè)實(shí)例節(jié)點(diǎn)距離最后一次有效回復(fù)PING命令的時(shí)間超過(guò)down-after-milliseconds選項(xiàng)所指定的值, 則這個(gè)實(shí)例會(huì)被哨兵標(biāo)記為主觀下線。

如果主庫(kù) 被標(biāo)記為主觀下線,則正在監(jiān)視這個(gè)主庫(kù)的所有哨兵要以每秒一次的頻率確認(rèn)主庫(kù)的確進(jìn)入了主觀下線狀態(tài)。

當(dāng)有足夠數(shù)量的哨兵(大于等于配置文件指定的值 )在指定的時(shí)間范圍內(nèi)確認(rèn)主庫(kù)的確進(jìn)入了主觀下線狀態(tài), 則主庫(kù)會(huì)被標(biāo)記為客觀下線 。

當(dāng)主庫(kù)被哨兵標(biāo)記為客觀下線 時(shí),就會(huì)進(jìn)入選主模式 。

若沒(méi)有足夠數(shù)量的哨兵同意主庫(kù)已經(jīng)進(jìn)入主觀下線, 主庫(kù)的主觀下線狀態(tài)就會(huì)被移除 ;若主庫(kù)重新向哨兵的PING命令返回有效回復(fù),主庫(kù)的主觀下線狀態(tài)就會(huì)被移除。

2.5 哨兵是如何選主的?

如果明確主庫(kù)已經(jīng)客觀下線了,哨兵就開(kāi)始了選主模式。

哨兵選主包括兩大過(guò)程,分別是:過(guò)濾和打分 。其實(shí)就是在多個(gè)從庫(kù)中,先按照一定的篩選條件,把不符合條件的從庫(kù)過(guò)濾 掉。然后再按照一定的規(guī)則,給剩下的從庫(kù)逐個(gè)打分,將得分最高的從庫(kù)選為新主庫(kù)

5ed6dfa4-08c1-11ee-962d-dac502259ad0.png

選主時(shí),會(huì)判斷從庫(kù)的狀態(tài),如果已經(jīng)下線,就直接過(guò)濾 。

如果從庫(kù)網(wǎng)絡(luò)不好,老是超時(shí),也會(huì)被過(guò)濾掉??催@個(gè)參數(shù)down-after-milliseconds,它表示我們認(rèn)定主從庫(kù)斷連的最大連接超時(shí)時(shí)間。

過(guò)濾掉了不適合做主庫(kù)的從庫(kù)后,就可以給剩下的從庫(kù)打分,按這三個(gè)規(guī)則打分:從庫(kù)優(yōu)先級(jí)、從庫(kù)復(fù)制進(jìn)度以及從庫(kù)ID號(hào) 。

從庫(kù)優(yōu)先級(jí)最高的話,打分就越高,優(yōu)先級(jí)可以通過(guò)slave-priority配置。如果優(yōu)先級(jí)一樣,就選與舊的主庫(kù)復(fù)制進(jìn)度最快的從庫(kù)。如果優(yōu)先級(jí)和從庫(kù)進(jìn)度都一樣,從庫(kù)ID 號(hào)小的打分高。

2.6 由哪個(gè)哨兵執(zhí)行主從切換呢?

一個(gè)哨兵標(biāo)記主庫(kù)為主觀下線 后,它會(huì)征求其他哨兵的意見(jiàn),確認(rèn)主庫(kù)是否的確進(jìn)入了主觀下線狀態(tài)。它向其他實(shí)例哨兵發(fā)送is-master-down-by-addr命令。其他哨兵會(huì)根據(jù)自己和主庫(kù)的連接情況,回應(yīng)Y或N(Y 表示贊成,N表示反對(duì)票)。如果這個(gè)哨兵獲取得足夠多的贊成票數(shù)(quorum配置),主庫(kù)會(huì)被標(biāo)記為客觀下線 。

標(biāo)記主庫(kù)客觀下線的這個(gè)哨兵,緊接著向其他哨兵發(fā)送命令,再發(fā)起投票 ,希望它可以來(lái)執(zhí)行主從切換。這個(gè)投票過(guò)程稱為Leader 選舉 。因?yàn)樽罱K執(zhí)行主從切換的哨兵稱為L(zhǎng)eader,投票過(guò)程就是確定Leader。一個(gè)哨兵想成為L(zhǎng)eader需要滿足兩個(gè)條件:

需要拿到num(sentinels)/2+1的贊成票。

并且拿到的票數(shù)需要大于等于哨兵配置文件中的quorum值。

舉個(gè)例子,假設(shè)有3個(gè)哨兵。配置的quorum值為2。即一個(gè)一個(gè)哨兵想成為L(zhǎng)eader至少需要拿到2張票。為了更好理解,大家可以看下

5f04d6ca-08c1-11ee-962d-dac502259ad0.png

在t1時(shí)刻,哨兵A1判斷主庫(kù)為客觀下線 ,它想成為主從切換的Leader,于是先給自己投一張贊成票,然后分別向哨兵A2 和A3發(fā)起投票命令,表示想成為 Leader。

在 t2 時(shí)刻,A3 判斷主庫(kù)為客觀下線 ,它也想成為 Leader,所以也先給自己投一張贊成票,再分別向 A1 和 A2 發(fā)起投票命令,表示也要成為 Leader。

在 t3 時(shí)刻,哨兵A1 收到了A3 的Leader投票請(qǐng)求。因?yàn)锳1已經(jīng)把票Y投給自己了,所以它不能再給其他哨兵投贊成票了,所以A1投票N給A3。

在 t4時(shí)刻,哨兵A2收到A3 的Leader投票請(qǐng)求,因?yàn)樯诒鳤2之前沒(méi)有投過(guò)票,它會(huì)給第一個(gè)向它發(fā)送投票請(qǐng)求的哨兵回復(fù)贊成票Y。

在 t5時(shí)刻,哨兵A2收到A1 的Leader投票請(qǐng)求,因?yàn)樯诒鳤2之前已經(jīng)投過(guò)贊成票給A3了,所以它只能給A1投反對(duì)票N。

最后t6時(shí)刻,哨兵A1只收到自己的一票Y贊成票,而哨兵A3得到兩張贊成票(A2和A3投的),因此哨兵A3成為了Leader 。

假設(shè)網(wǎng)絡(luò)故障等原因,哨兵A3也沒(méi)有收到兩張票 ,那么這輪投票就不會(huì)產(chǎn)生Leader。哨兵集群會(huì)等待一段時(shí)間(一般是哨兵故障轉(zhuǎn)移超時(shí)時(shí)間的2倍),再進(jìn)行重新選舉。

2.7 故障轉(zhuǎn)移

假設(shè)哨兵模式架構(gòu)如下,有三個(gè)哨兵,一個(gè)主庫(kù)M,兩個(gè)從庫(kù)S1和S2。

5f22cefa-08c1-11ee-962d-dac502259ad0.png

當(dāng)哨兵檢測(cè)到Redis主庫(kù)M1出現(xiàn)故障,那么哨兵需要對(duì)集群進(jìn)行故障轉(zhuǎn)移。假設(shè)選出了哨兵3 作為L(zhǎng)eader。故障轉(zhuǎn)移流程如下:

5f47d70e-08c1-11ee-962d-dac502259ad0.png

從庫(kù)S1解除從節(jié)點(diǎn)身份,升級(jí)為新主庫(kù)

從庫(kù)S2成為新主庫(kù)的從庫(kù)

原主節(jié)點(diǎn)恢復(fù)也變成新主庫(kù)的從節(jié)點(diǎn)

通知客戶端應(yīng)用程序新主節(jié)點(diǎn)的地址。

故障轉(zhuǎn)移后:

5f6a59d2-08c1-11ee-962d-dac502259ad0.png

3.Redis Cluster集群

哨兵模式基于主從模式,實(shí)現(xiàn)讀寫(xiě)分離,它還可以自動(dòng)切換,系統(tǒng)可用性更高。但是它每個(gè)節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)是一樣的,浪費(fèi)內(nèi)存,并且不好在線擴(kuò)容 。因此,Reids Cluster集群(切片集群的實(shí)現(xiàn)方案) 應(yīng)運(yùn)而生,它在Redis3.0加入的,實(shí)現(xiàn)了Redis的分布式存儲(chǔ) 。對(duì)數(shù)據(jù)進(jìn)行分片,也就是說(shuō)每臺(tái)Redis節(jié)點(diǎn)上存儲(chǔ)不同的內(nèi)容,來(lái)解決在線擴(kuò)容的問(wèn)題。并且,它可以保存大量數(shù)據(jù) ,即分散數(shù)據(jù)到各個(gè)Redis實(shí)例,還提供復(fù)制和故障轉(zhuǎn)移的功能。

比如你一個(gè)Redis實(shí)例保存15G甚至更大的數(shù)據(jù),響應(yīng)就會(huì)很慢,這是因?yàn)镽edis RDB 持久化機(jī)制導(dǎo)致的,Redis會(huì)fork子進(jìn)程完成 RDB 持久化操作,fork執(zhí)行的耗時(shí)與 Redis 數(shù)據(jù)量成正相關(guān)。

這時(shí)候你很容易想到,把15G數(shù)據(jù)分散來(lái)存儲(chǔ)就好了嘛。這就是Redis切片集群 的初衷。切片集群是啥呢?來(lái)看個(gè)例子,如果你要用Redis保存15G的數(shù)據(jù),可以用單實(shí)例Redis,或者3臺(tái)Redis實(shí)例組成切片集群 ,對(duì)比如下:

切片集群和Redis Cluster 的區(qū)別:Redis Cluster是從Redis3.0版本開(kāi)始,官方提供的一種實(shí)現(xiàn)切片集群 的方案。

5f863152-08c1-11ee-962d-dac502259ad0.png

既然數(shù)據(jù)是分片分布到不同Redis實(shí)例的,那客戶端到底是怎么確定想要訪問(wèn)的數(shù)據(jù)在哪個(gè)實(shí)例上呢?我們一起來(lái)看下Reids Cluster 是怎么做的哈。

3.1 哈希槽(Hash Slot)

Redis Cluster方案采用哈希槽(Hash Slot),來(lái)處理數(shù)據(jù)和實(shí)例之間的映射關(guān)系。

一個(gè)切片集群被分為16384個(gè)slot(槽),每個(gè)進(jìn)入Redis的鍵值對(duì),根據(jù)key進(jìn)行散列,分配到這16384插槽中的一個(gè)。使用的哈希映射也比較簡(jiǎn)單,用CRC16算法計(jì)算出一個(gè)16bit的值,再對(duì)16384取模。數(shù)據(jù)庫(kù)中的每個(gè)鍵都屬于這16384個(gè)槽的其中一個(gè),集群中的每個(gè)節(jié)點(diǎn)都可以處理這16384個(gè)槽。

集群中的每個(gè)節(jié)點(diǎn)負(fù)責(zé)一部分的哈希槽,假設(shè)當(dāng)前集群有A、B、C3個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)上負(fù)責(zé)的哈希槽數(shù) =16384/3,那么可能存在的一種分配:

節(jié)點(diǎn)A負(fù)責(zé)0~5460號(hào)哈希槽

節(jié)點(diǎn)B負(fù)責(zé)5461~10922號(hào)哈希槽

節(jié)點(diǎn)C負(fù)責(zé)10923~16383號(hào)哈希槽

客戶端給一個(gè)Redis實(shí)例發(fā)送數(shù)據(jù)讀寫(xiě)操作時(shí),如果這個(gè)實(shí)例上并沒(méi)有相應(yīng)的數(shù)據(jù),會(huì)怎么樣呢?MOVED重定向和ASK重定向了解一下哈

3.2 MOVED重定向和ASK重定向

在Redis cluster模式下,節(jié)點(diǎn)對(duì)請(qǐng)求的處理過(guò)程如下:

通過(guò)哈希槽映射,檢查當(dāng)前Redis key是否存在當(dāng)前節(jié)點(diǎn)

若哈希槽不是由自身節(jié)點(diǎn)負(fù)責(zé),就返回MOVED重定向

若哈希槽確實(shí)由自身負(fù)責(zé),且key在slot中,則返回該key對(duì)應(yīng)結(jié)果

若Redis key不存在此哈希槽中,檢查該哈希槽是否正在遷出(MIGRATING)?

若Redis key正在遷出,返回ASK錯(cuò)誤重定向客戶端到遷移的目的服務(wù)器上

若哈希槽未遷出,檢查哈希槽是否導(dǎo)入中?

若哈希槽導(dǎo)入中且有ASKING標(biāo)記,則直接操作,否則返回MOVED重定向

3.2.1 Moved 重定向

客戶端給一個(gè)Redis實(shí)例發(fā)送數(shù)據(jù)讀寫(xiě)操作時(shí),如果計(jì)算出來(lái)的槽不是在該節(jié)點(diǎn)上,這時(shí)候它會(huì)返回MOVED重定向錯(cuò)誤,MOVED重定向錯(cuò)誤中,會(huì)將哈希槽所在的新實(shí)例的IP和port端口帶回去。這就是Redis Cluster的MOVED重定向機(jī)制。流程圖如下:

5fb0958c-08c1-11ee-962d-dac502259ad0.png

3.2.2 ASK 重定向

Ask重定向一般發(fā)生于集群伸縮的時(shí)候。集群伸縮會(huì)導(dǎo)致槽遷移,當(dāng)我們?nèi)ピ垂?jié)點(diǎn)訪問(wèn)時(shí),此時(shí)數(shù)據(jù)已經(jīng)可能已經(jīng)遷移到了目標(biāo)節(jié)點(diǎn),使用Ask重定向 可以解決此種情況。

5fcd4c0e-08c1-11ee-962d-dac502259ad0.png

3.3 Cluster集群節(jié)點(diǎn)的通訊協(xié)議:Gossip

一個(gè)Redis集群由多個(gè)節(jié)點(diǎn)組成,各個(gè)節(jié)點(diǎn)之間是怎么通信的呢?通過(guò)Gossip協(xié)議 !Gossip是一種謠言傳播協(xié)議,每個(gè)節(jié)點(diǎn)周期性地從節(jié)點(diǎn)列表中選擇 k 個(gè)節(jié)點(diǎn),將本節(jié)點(diǎn)存儲(chǔ)的信息傳播出去,直到所有節(jié)點(diǎn)信息一致,即算法收斂了。

Gossip協(xié)議基本思想:一個(gè)節(jié)點(diǎn)想要分享一些信息給網(wǎng)絡(luò)中的其他的一些節(jié)點(diǎn)。于是,它周期性的隨機(jī)選擇一些節(jié)點(diǎn),并把信息傳遞給這些節(jié)點(diǎn)。這些收到信息的節(jié)點(diǎn)接下來(lái)會(huì)做同樣的事情,即把這些信息傳遞給其他一些隨機(jī)選擇的節(jié)點(diǎn)。一般而言,信息會(huì)周期性的傳遞給N個(gè)目標(biāo)節(jié)點(diǎn),而不只是一個(gè)。這個(gè)N被稱為fanout

Redis Cluster集群通過(guò)Gossip協(xié)議進(jìn)行通信,節(jié)點(diǎn)之前不斷交換信息,交換的信息內(nèi)容包括節(jié)點(diǎn)出現(xiàn)故障、新節(jié)點(diǎn)加入、主從節(jié)點(diǎn)變更信息、slot信息 等等。gossip協(xié)議包含多種消息類型,包括ping,pong,meet,fail,等等

600ea550-08c1-11ee-962d-dac502259ad0.png

meet消息:通知新節(jié)點(diǎn)加入。消息發(fā)送者通知接收者加入到當(dāng)前集群,meet消息通信正常完成后,接收節(jié)點(diǎn)會(huì)加入到集群中并進(jìn)行周期性的ping、pong消息交換。

ping消息:節(jié)點(diǎn)每秒會(huì)向集群中其他節(jié)點(diǎn)發(fā)送 ping 消息,消息中帶有自己已知的兩個(gè)節(jié)點(diǎn)的地址、槽、狀態(tài)信息、最后一次通信時(shí)間等

pong消息:當(dāng)接收到ping、meet消息時(shí),作為響應(yīng)消息回復(fù)給發(fā)送方確認(rèn)消息正常通信。消息中同樣帶有自己已知的兩個(gè)節(jié)點(diǎn)信息。

fail消息:當(dāng)節(jié)點(diǎn)判定集群內(nèi)另一個(gè)節(jié)點(diǎn)下線時(shí),會(huì)向集群內(nèi)廣播一個(gè)fail消息,其他節(jié)點(diǎn)接收到fail消息之后把對(duì)應(yīng)節(jié)點(diǎn)更新為下線狀態(tài)。

特別的,每個(gè)節(jié)點(diǎn)是通過(guò)集群總線(cluster bus) 與其他的節(jié)點(diǎn)進(jìn)行通信的。通訊時(shí),使用特殊的端口號(hào),即對(duì)外服務(wù)端口號(hào)加10000。例如如果某個(gè)node的端口號(hào)是6379,那么它與其它nodes通信的端口號(hào)是 16379。nodes 之間的通信采用特殊的二進(jìn)制協(xié)議。

3.4 故障轉(zhuǎn)移

Redis集群實(shí)現(xiàn)了高可用,當(dāng)集群內(nèi)節(jié)點(diǎn)出現(xiàn)故障時(shí),通過(guò)故障轉(zhuǎn)移 ,以保證集群正常對(duì)外提供服務(wù)。

redis集群通過(guò)ping/pong消息,實(shí)現(xiàn)故障發(fā)現(xiàn)。這個(gè)環(huán)境包括主觀下線和客觀下線 。

主觀下線: 某個(gè)節(jié)點(diǎn)認(rèn)為另一個(gè)節(jié)點(diǎn)不可用,即下線狀態(tài),這個(gè)狀態(tài)并不是最終的故障判定,只能代表一個(gè)節(jié)點(diǎn)的意見(jiàn),可能存在誤判情況。

602fbde4-08c1-11ee-962d-dac502259ad0.png主觀下線

客觀下線: 指標(biāo)記一個(gè)節(jié)點(diǎn)真正的下線,集群內(nèi)多個(gè)節(jié)點(diǎn)都認(rèn)為該節(jié)點(diǎn)不可用,從而達(dá)成共識(shí)的結(jié)果。如果是持有槽的主節(jié)點(diǎn)故障,需要為該節(jié)點(diǎn)進(jìn)行故障轉(zhuǎn)移。

假如節(jié)點(diǎn)A標(biāo)記節(jié)點(diǎn)B為主觀下線,一段時(shí)間后,節(jié)點(diǎn)A通過(guò)消息把節(jié)點(diǎn)B的狀態(tài)發(fā)到其它節(jié)點(diǎn),當(dāng)節(jié)點(diǎn)C接受到消息并解析出消息體時(shí),如果發(fā)現(xiàn)節(jié)點(diǎn)B的pfail狀態(tài)時(shí),會(huì)觸發(fā)客觀下線流程;

當(dāng)下線為主節(jié)點(diǎn)時(shí),此時(shí)Redis Cluster集群為統(tǒng)計(jì)持有槽的主節(jié)點(diǎn)投票,看投票數(shù)是否達(dá)到一半,當(dāng)下線報(bào)告統(tǒng)計(jì)數(shù)大于一半時(shí),被標(biāo)記為客觀下線 狀態(tài)。

流程如下:

6053ae84-08c1-11ee-962d-dac502259ad0.png客觀下線

故障恢復(fù) :故障發(fā)現(xiàn)后,如果下線節(jié)點(diǎn)的是主節(jié)點(diǎn),則需要在它的從節(jié)點(diǎn)中選一個(gè)替換它,以保證集群的高可用。流程如下:

6085004c-08c1-11ee-962d-dac502259ad0.png

資格檢查:檢查從節(jié)點(diǎn)是否具備替換故障主節(jié)點(diǎn)的條件。

準(zhǔn)備選舉時(shí)間:資格檢查通過(guò)后,更新觸發(fā)故障選舉時(shí)間。

發(fā)起選舉:到了故障選舉時(shí)間,進(jìn)行選舉。

選舉投票:只有持有槽的主節(jié)點(diǎn) 才有票,從節(jié)點(diǎn)收集到足夠的選票(大于一半),觸發(fā)替換主節(jié)點(diǎn)操作

3.5 加餐:為什么Redis Cluster的Hash Slot 是16384?

對(duì)于客戶端請(qǐng)求過(guò)來(lái)的鍵值key,哈希槽=CRC16(key) % 16384,CRC16算法產(chǎn)生的哈希值是16bit的,按道理該算法是可以產(chǎn)生2^16=65536個(gè)值,為什么不用65536,用的是16384(2^14)呢?

大家可以看下作者的原始回答:

609dde78-08c1-11ee-962d-dac502259ad0.png

Redis 每個(gè)實(shí)例節(jié)點(diǎn)上都保存對(duì)應(yīng)有哪些slots,它是一個(gè) unsigned char slots[REDIS_CLUSTER_SLOTS/8] 類型60bf0260-08c1-11ee-962d-dac502259ad0.png

在redis節(jié)點(diǎn)發(fā)送心跳包時(shí)需要把所有的槽放到這個(gè)心跳包里,如果slots數(shù)量是 65536 ,占空間= 65536 / 8(一個(gè)字節(jié)8bit) / 1024(1024個(gè)字節(jié)1kB) =8kB ,如果使用slots數(shù)量是 16384 ,所占空間 = 16384 / 8(每個(gè)字節(jié)8bit) / 1024(1024個(gè)字節(jié)1kB) = 2kB ,可見(jiàn)16384個(gè)slots比 65536省 6kB內(nèi)存左右,假如一個(gè)集群有100個(gè)節(jié)點(diǎn),那每個(gè)實(shí)例里就省了600kB啦

一般情況下Redis cluster集群主節(jié)點(diǎn)數(shù)量基本不可能超過(guò)1000個(gè),超過(guò)1000會(huì)導(dǎo)致網(wǎng)絡(luò)擁堵。對(duì)于節(jié)點(diǎn)數(shù)在1000以內(nèi)的Redis cluster集群,16384個(gè)槽位其實(shí)夠用了。

既然為了節(jié)省內(nèi)存網(wǎng)絡(luò)開(kāi)銷,為什么 slots不選擇用8192(即16384/2) 呢?

8192 / 8(每個(gè)字節(jié)8bit) / 1024(1024個(gè)字節(jié)1kB) = 1kB ,只需要1KB!可以先看下Redis 把 Key 換算成所屬 slots 的方法

unsignedintkeyHashSlot(char*key,intkeylen){
ints,e;/*start-endindexesof{and}*/

for(s=0;s

Redis 將key換算成slots 的方法:其實(shí)就是是將crc16(key) 之后再和slots的數(shù)量進(jìn)行與計(jì)算

這里為什么用0x3FFF(16383) 來(lái)計(jì)算,而不是16384呢?因?yàn)樵诓划a(chǎn)生溢出的情況下 x % (2^n)等價(jià)于x & (2^n - 1)即 x % 16384 == x & 16383

那到底為什么不用8192呢?

crc16 出來(lái)結(jié)果,理論上出現(xiàn)重復(fù)的概率為 1?65536,但實(shí)際結(jié)果重復(fù)概率可能比這個(gè)大不少,就像crc32 結(jié)果 理論上 1/40億 分之一,但實(shí)際有人測(cè)下來(lái)10萬(wàn)碰撞的概率就比較大了。假如 slots 設(shè)置成 8192, 200個(gè)實(shí)例的節(jié)點(diǎn)情況下,理論值是 每40個(gè)不同key請(qǐng)求,命中就會(huì)失效一次,假如節(jié)點(diǎn)數(shù)增加到400,那就是20個(gè)請(qǐng)求。并且1kb 并不會(huì)比 2k 省太多,性價(jià)比不是特別高,所以可能 選16384會(huì)更為通用一點(diǎn)

責(zé)任編輯:彭菁

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 管理系統(tǒng)
    +關(guān)注

    關(guān)注

    1

    文章

    2691

    瀏覽量

    36487
  • 小程序
    +關(guān)注

    關(guān)注

    1

    文章

    241

    瀏覽量

    12576
  • Redis
    +關(guān)注

    關(guān)注

    0

    文章

    381

    瀏覽量

    11137

原文標(biāo)題:Redis主從、哨兵、 Cluster集群一鍋端!

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 0人收藏

    評(píng)論

    相關(guān)推薦

    redis集群環(huán)境安裝及配置

    redis集群主從配置
    發(fā)表于 03-08 09:59

    redis集群的兩種備份方式

    redis集群 主從同步 備份
    發(fā)表于 04-17 13:30

    Redis-cluster在線集群安裝

    Redis-cluster之在線搭建詳解
    發(fā)表于 06-06 14:52

    3分鐘搭建Redis Cluster集群

    Redis Cluster集群快速搭建
    發(fā)表于 06-12 14:58

    Redis主從復(fù)制的作用和步驟

    Redis青銅修煉手冊(cè)(五) --- Redis主從復(fù)制
    發(fā)表于 06-27 07:20

    redis集群的如何部署

    redis集群的部署(偽分布式)
    發(fā)表于 05-29 17:13

    Redis集群相關(guān)問(wèn)題的解決

    Redis 集群相關(guān)問(wèn)題
    發(fā)表于 06-11 10:09

    Redis Cluster的基本原理及實(shí)現(xiàn)細(xì)節(jié)

    Redis Cluster的基本原理和架構(gòu) Redis Cluster是分布式Redis的實(shí)現(xiàn)。隨著Re
    發(fā)表于 09-28 19:09 ?0次下載
    <b class='flag-5'>Redis</b> <b class='flag-5'>Cluster</b>的基本原理及實(shí)現(xiàn)細(xì)節(jié)

    Redis的四種模式復(fù)制、哨兵、Cluster以及集群模式

    概述 Redis作為緩存的高效中間件,在我們?nèi)粘5拈_(kāi)發(fā)中被頻繁的使用,今天就來(lái)說(shuō)一說(shuō)Redis的四種模式,分別是「單機(jī)版、主從復(fù)制、哨兵、以及集群
    的頭像 發(fā)表于 09-30 17:51 ?2717次閱讀
    <b class='flag-5'>Redis</b>的四種模式復(fù)制、<b class='flag-5'>哨兵</b>、<b class='flag-5'>Cluster</b>以及<b class='flag-5'>集群</b>模式

    什么是Redis主從復(fù)制

    Master節(jié)點(diǎn)的能力,主掛了服務(wù)就不可以寫(xiě)數(shù)據(jù)了。僅僅就是增強(qiáng)了應(yīng)用讀數(shù)據(jù)的并發(fā)量同時(shí)做數(shù)據(jù)備份。 一般生產(chǎn)環(huán)境會(huì)采用 哨兵 或者 Redis Cluster 這種具備Master自動(dòng)選舉的方案,我們學(xué)習(xí)時(shí)還是要掌握
    的頭像 發(fā)表于 10-09 15:09 ?504次閱讀
    什么是<b class='flag-5'>Redis</b><b class='flag-5'>主從</b>復(fù)制

    Cloud MemoryStore for Redis Cluster 正式發(fā)布

    提供 99.99% 的 SLA。借助 Memorystore for Redis Cluster,您可以獲得完全托管且完全開(kāi)源軟件 (OSS) 兼容的 Redis 集群產(chǎn)品,具有零停機(jī)
    的頭像 發(fā)表于 11-24 17:40 ?496次閱讀
    Cloud MemoryStore for <b class='flag-5'>Redis</b> <b class='flag-5'>Cluster</b> 正式發(fā)布

    redis集群狀態(tài)查看命令

    的文章。 Redis集群狀態(tài)查看命令有多種,在本文中我們將詳細(xì)介紹以下命令: CLUSTER INFO: 這個(gè)命令可以用于查看整個(gè)集群的信息。運(yùn)行這個(gè)命令后,
    的頭像 發(fā)表于 12-04 10:44 ?1536次閱讀

    redis查看集群狀態(tài)命令

    Redis 集群管理時(shí),了解集群的狀態(tài)是非常重要的,可以通過(guò)一些命令來(lái)獲取集群的狀態(tài)信息。本文將詳細(xì)介紹 Redis 查看
    的頭像 發(fā)表于 12-04 11:39 ?1365次閱讀

    redis哨兵集群有什么區(qū)別

    Redis是一個(gè)開(kāi)源的內(nèi)存數(shù)據(jù)庫(kù),被廣泛用于構(gòu)建高性能和可擴(kuò)展的應(yīng)用程序。在使用Redis時(shí),有兩種常見(jiàn)的架構(gòu)模式:哨兵集群。雖然這兩種模式都有助于提高可用性和性能,但它們?cè)谠O(shè)計(jì)和實(shí)
    的頭像 發(fā)表于 12-04 14:53 ?3123次閱讀

    Redis Cluster之故障轉(zhuǎn)移

    1. Redis Cluster 簡(jiǎn)介 Redis ClusterRedis 官方提供的 Redi
    的頭像 發(fā)表于 01-20 09:21 ?578次閱讀
    <b class='flag-5'>Redis</b> <b class='flag-5'>Cluster</b>之故障轉(zhuǎn)移

    電子發(fā)燒友

    中國(guó)電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會(huì)員交流學(xué)習(xí)
    • 獲取您個(gè)性化的科技前沿技術(shù)信息
    • 參加活動(dòng)獲取豐厚的禮品