10.全網(wǎng)最容易理解的Redis主從復(fù)制原理(高頻面試題)

主從復(fù)制

如果 Redis 的讀寫(xiě)請(qǐng)求量很大,那么單個(gè) Redis 實(shí)例很有可能承擔(dān)不了這么大的請(qǐng)求量,如何提高Redis的性能呢?我們可以部署多個(gè)副本節(jié)點(diǎn),業(yè)務(wù)采用讀寫(xiě)分離的方式,把讀請(qǐng)求分擔(dān)到多個(gè)副本節(jié)點(diǎn)上,提高訪問(wèn)性能。要實(shí)現(xiàn)讀寫(xiě)分離,就必須部署多個(gè)副本,每個(gè)副本需要實(shí)時(shí)同步主節(jié)點(diǎn)的數(shù)據(jù)。

單可用區(qū)(節(jié)點(diǎn)全部在一個(gè)可用區(qū)):無(wú)法應(yīng)對(duì)機(jī)房級(jí)別的故障


1541628331324_.pic.jpg

如果上??捎脜^(qū)機(jī)房出現(xiàn)故障,整個(gè)Redis服務(wù)全部癱瘓,所以我們?cè)谄綍r(shí)部署時(shí),需要把節(jié)點(diǎn)分散在不同的可用區(qū),如果有小伙伴公司對(duì)可用性要求極高,可以研究下異地多活方案,在這里我就不展開(kāi)了。

主從復(fù)制的三種方式:

①全量復(fù)制

②增量復(fù)制

③無(wú)盤(pán)復(fù)制

1.全量復(fù)制

假設(shè)我們有兩個(gè)節(jié)點(diǎn),A節(jié)點(diǎn)是 Master 節(jié)點(diǎn),B節(jié)點(diǎn)是 Slave 節(jié)點(diǎn)。

當(dāng)我們?cè)诠?jié)點(diǎn)B上執(zhí)行slaveof命令后,節(jié)點(diǎn)B會(huì)與節(jié)點(diǎn)A建立一個(gè)TCP連接,然后發(fā)送psync ${runid} ${offset}命令,告知節(jié)點(diǎn)A需要開(kāi)始同步數(shù)據(jù)。

參數(shù)介紹:

  • runid:每個(gè) Redis 實(shí)例啟動(dòng)時(shí)都會(huì)自動(dòng)生成的一個(gè)隨機(jī) ID,用來(lái)唯一標(biāo)記這個(gè)實(shí)例
  • offset:偏移量,slave需要從哪個(gè)位置開(kāi)始同步數(shù)據(jù)
1241627715863_.pic.jpg

由于是第一次同步,Slave 節(jié)點(diǎn)不知道 Master節(jié)點(diǎn)的runid,所以 Slave 節(jié)點(diǎn)會(huì)發(fā)送psync ? -1,表示需要全量同步數(shù)據(jù)。

Master 節(jié)點(diǎn)在收到 Slave 節(jié)點(diǎn)發(fā)來(lái)的psync后,會(huì)給slave回復(fù)+fullresync ${runid} ${offset},這個(gè)runid就是master的唯一標(biāo)識(shí),slave會(huì)記錄這個(gè)runid,用于后續(xù)斷線(xiàn)重連同步請(qǐng)求。

Master 執(zhí)行 bgsave 命令,生成 RDB 文件,接著將文件發(fā)給 Slave。Slave 接收到 RDB 文件后,會(huì)先清空當(dāng)前數(shù)據(jù)庫(kù),然后加載 RDB 文件。這是因?yàn)镾lave在通過(guò) replicaof 命令開(kāi)始和 Master 同步前,可能保存了其他數(shù)據(jù)。為了避免之前數(shù)據(jù)的影響,Slave 需要先把當(dāng)前數(shù)據(jù)庫(kù)清空。

在 Master 將數(shù)據(jù)同步給 Slave 的過(guò)程中,Master 不會(huì)被阻塞,仍然可以正常接收請(qǐng)求。否則,Redis 的服務(wù)就被中斷了。但是,這些請(qǐng)求中的寫(xiě)操作并沒(méi)有記錄到剛剛生成的 RDB 文件中。為了保證主 Slave 的數(shù)據(jù)一致性,Master 會(huì)在內(nèi)存中用 repl_backlog_buffer 記錄 RDB 文件生成后收到的所有寫(xiě)操作。

最后,Master 會(huì)把 repl_backlog_buffer數(shù)據(jù)再發(fā)送給從庫(kù)。這樣一來(lái),主從庫(kù)就實(shí)現(xiàn)同步了。

全量復(fù)制的開(kāi)銷(xiāo):

主節(jié)點(diǎn):生成RDB文件會(huì)占用內(nèi)存、硬盤(pán)資源,網(wǎng)絡(luò)傳輸RDB的時(shí)候會(huì)占用一定的網(wǎng)絡(luò)帶寬資源

從節(jié)點(diǎn):清空數(shù)據(jù),若數(shù)據(jù)量大,需要消耗一定的時(shí)間,加載RDB也需要一定的時(shí)間

2.增量同步

在 Redis 2.8 之前,如果主從庫(kù)在命令傳播時(shí)出現(xiàn)了網(wǎng)絡(luò)閃斷,從庫(kù)就會(huì)和主庫(kù)重新進(jìn)行一次全量復(fù)制,開(kāi)銷(xiāo)非常大。

在Redis在這方面進(jìn)行了改進(jìn),在2.8版本之后,Redis支持增量同步

1251627715877_.pic.jpg

主從因?yàn)楣收蠑嚅_(kāi),故障恢復(fù)后,他們重新建立連接,Slave 節(jié)點(diǎn)向 Master 節(jié)點(diǎn)發(fā)送數(shù)據(jù) 同步請(qǐng)求:psync ${runid} ${offset},Master 收到psync命令之后,檢查slave發(fā)來(lái)的runid與自身的runid一致,如果一致,說(shuō)明之前已經(jīng)同步過(guò)數(shù)據(jù),這次只需要同步部分?jǐn)?shù)據(jù)即可。

這里分為兩種情況:
①如果offset在repl_backlog_buffer范圍內(nèi),那么 Master 節(jié)點(diǎn)給 Slave 節(jié)點(diǎn)回復(fù)+continue,表示這次只同步部分?jǐn)?shù)據(jù)。之后 Master 節(jié)點(diǎn)把復(fù)制緩沖區(qū)offset之后的數(shù)據(jù)給 Slave 節(jié)點(diǎn),接下來(lái) Slave 節(jié)點(diǎn)執(zhí)行這些命令后就與 Master 數(shù)據(jù)一致了。

②如果offset不在repl_backlog_buffer范圍內(nèi),說(shuō)明斷開(kāi)連接很久了,如果offset在repl_backlog_buffer的內(nèi)容已經(jīng)被新的內(nèi)容覆蓋了,此時(shí)只能觸發(fā)全量數(shù)據(jù)同步。

3.無(wú)盤(pán)復(fù)制

通常,全量復(fù)制需要在磁盤(pán)上創(chuàng)建RDB文件,然后加載到內(nèi)存中,Redis支持無(wú)盤(pán)復(fù)制,生成的RDB文件不保存到磁盤(pán)而是直接通過(guò)網(wǎng)絡(luò)發(fā)送給從節(jié)點(diǎn)。無(wú)盤(pán)復(fù)制適用于主節(jié)點(diǎn)所在機(jī)器磁盤(pán)性能較差但網(wǎng)絡(luò)寬帶較充裕的場(chǎng)景。需要注意的是,無(wú)盤(pán)復(fù)制目前依然處于實(shí)驗(yàn)階段

?著作權(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)容