Redis源碼剖析之主從復(fù)制

2.數(shù)據(jù)庫狀態(tài)一致

主從復(fù)制,服務(wù)器雙方數(shù)據(jù)庫將保存相同的數(shù)據(jù),這種現(xiàn)象稱為“數(shù)據(jù)庫狀態(tài)一致”

3.執(zhí)行方式

>>>slaveof 127.0.0.1 6379

4.舊版復(fù)制功能的實(shí)現(xiàn)(2.8以前的版本)

復(fù)制功能都分為兩個(gè)基本步驟:同步和命令傳播

同步:將從服務(wù)器的數(shù)據(jù)庫狀態(tài)更新至主服務(wù)器當(dāng)前所處的數(shù)據(jù)庫狀態(tài)。

命令傳播:主服務(wù)器的數(shù)據(jù)庫狀態(tài)被修改,導(dǎo)致主從服務(wù)器的數(shù)據(jù)庫狀態(tài)不一致,讓主從服務(wù)器數(shù)據(jù)庫重新回到一致狀態(tài)。

1.同步

當(dāng)客戶端向從服務(wù)器發(fā)送slaveof命令,要求從服務(wù)器復(fù)制主服務(wù)器時(shí),從服務(wù)器首先需要執(zhí)行同步操作,也就是將從服務(wù)器的數(shù)據(jù)庫狀態(tài)更新至主服務(wù)器當(dāng)前所處的數(shù)據(jù)庫狀態(tài)。而從服務(wù)器對主服務(wù)器的同步操作需要通過向主服務(wù)器發(fā)送SYNC命令來完成。

從服務(wù)器發(fā)送SYNC命令的執(zhí)行步驟:

a.從服務(wù)器向主服務(wù)器發(fā)送SYNC命令。

b.收到SYNC命令的主服務(wù)器執(zhí)行BGSAVE命令,在后臺生成一個(gè)RDB文件,并使用一個(gè)緩沖區(qū)記錄從現(xiàn)在開始執(zhí)行的所有寫命令。

c.當(dāng)主服務(wù)器的BGSAVE命令執(zhí)行完畢時(shí),主服務(wù)器會將BGSAVE命令生成的RDB文件發(fā)送給從服務(wù)器,從服務(wù)器接收接收并載入這個(gè)RBD文件,將自己的數(shù)據(jù)庫狀態(tài)更新至主服務(wù)器執(zhí)行BGSAVE命令時(shí)的數(shù)據(jù)庫狀態(tài)。

d.主服務(wù)器將記錄在緩沖區(qū)里面的所有寫命令發(fā)送給從服務(wù)器,從服務(wù)器執(zhí)行這些寫命令,將自己的數(shù)據(jù)庫狀態(tài)更新至主服務(wù)器當(dāng)前所處的狀態(tài)。

2.命令傳播

在執(zhí)行完同步操作以后,如果客戶端又再次向主服務(wù)器發(fā)送寫命令,如果此時(shí)該命令沒有傳播到從服務(wù)器,那么主從服務(wù)器的數(shù)據(jù)庫狀態(tài)必然會不一樣,因此,在執(zhí)行完同步操作以后,還必須得執(zhí)行命令傳播,用來傳播主服務(wù)器接收到的新的命令請求。

為了讓主從服務(wù)器再次回到一致狀態(tài),主服務(wù)器需要對從服務(wù)器執(zhí)行命令傳播操作:主服務(wù)器會將自己執(zhí)行的那條寫命令,發(fā)送給從服務(wù)器,當(dāng)從服務(wù)器執(zhí)行了相同的寫命令之后,主從服務(wù)器將再次回到一致狀態(tài)。

3.舊版復(fù)制存在的缺陷

從服務(wù)器對主服務(wù)器的復(fù)制分為以下兩種:

初次復(fù)制:從服務(wù)器沒有復(fù)制任何主服務(wù)器,或者從服務(wù)器當(dāng)前要復(fù)制的主服務(wù)器和上一次復(fù)制的主服務(wù)器不同。

斷線后重復(fù)制: 處理命令傳播階段的主從服務(wù)器因?yàn)榫W(wǎng)絡(luò)原因而中斷了復(fù)制,但從服務(wù)器通過自動(dòng)重連接重新連接上主服務(wù)器,并繼續(xù)復(fù)制主服務(wù)器 。

當(dāng)主從服務(wù)器斷開以后,從服務(wù)器通過自動(dòng)重連連上主服務(wù)器,然后從服務(wù)器向主服務(wù)器發(fā)送SYNC命令,進(jìn)行同步操作,但是主服務(wù)器此時(shí)會將數(shù)據(jù)庫狀態(tài)寫入到RDB文件中,如上述紅色方框(重復(fù)復(fù)制了許多鍵值對),這部分就是舊版復(fù)制存在的缺陷。

4.舊版復(fù)制問題的解決方案

為了解決舊版復(fù)制功能在處理斷線重復(fù)復(fù)制情況時(shí)的低效問題,redis從2.8以后,使用PSYNC命令代替SYNC命令來執(zhí)行復(fù)制時(shí)的同步操作。

psync命令具有完整重同步和部分重同步兩種模式。

完整重同步:用以解決初次復(fù)制的問題。執(zhí)行操作與sync一模一樣。

部分重同步:用于處理斷線后重復(fù)制情況:當(dāng)從服務(wù)器在斷線后重新連上主服務(wù)器時(shí),如果條件允許,主服務(wù)器可以將主從服務(wù)器連接斷開期間執(zhí)行的寫命令發(fā)送給從服務(wù)器,從服務(wù)器只要接收并執(zhí)行這些寫命令,就可以將數(shù)據(jù)更新至主服務(wù)器當(dāng)前所處的狀態(tài)。

PSYNC命令的部分重同步解決了舊版復(fù)制功能在處理斷線后重復(fù)復(fù)制時(shí)出現(xiàn)的低效情況。

主從服務(wù)器執(zhí)行部分重同步的過程:

5.部分重同步的實(shí)現(xiàn)

要實(shí)現(xiàn)部分重同步,必須解決以下三個(gè)問題:

1.當(dāng)前主從服務(wù)器各復(fù)制了多少數(shù)據(jù)??

2.如果主從服務(wù)器斷線以后,主服務(wù)器新接收到的命令請求,該如何處理?

3.如果在一個(gè)集群系統(tǒng)中,如何找到上一次復(fù)制的那個(gè)主服務(wù)器呢?

部分重同步功能由以下三個(gè)部分構(gòu)成:

a.主服務(wù)器的復(fù)制偏移量和從服務(wù)器的復(fù)制偏移量

b.主服務(wù)器的復(fù)制積壓緩沖區(qū)

c.服務(wù)器的運(yùn)行ID

typedef struct redisClient {

// 復(fù)制狀態(tài)

int replstate; /* replication state if this is a slave */

// 用于保存主服務(wù)器傳來的 RDB 文件的文件描述符

int repldbfd; /* replication DB file descriptor */

// 讀取主服務(wù)器傳來的 RDB 文件的偏移量

off_t repldboff; /* replication DB file offset */

// 主服務(wù)器傳來的 RDB 文件的大小

off_t repldbsize; /* replication DB file size */

sds replpreamble; /* replication DB preamble. */

// 主服務(wù)器的復(fù)制偏移量

long long reploff; /* replication offset if this is our master */

// 從服務(wù)器最后一次發(fā)送 REPLCONF ACK 時(shí)的偏移量

long long repl_ack_off; /* replication ack offset, if this is a slave */

// 從服務(wù)器最后一次發(fā)送 REPLCONF ACK 的時(shí)間

long long repl_ack_time;/* replication ack time, if this is a slave */

// 主服務(wù)器的 master run ID

// 保存在客戶端,用于執(zhí)行部分重同步

char replrunid[REDIS_RUN_ID_SIZE+1]; /* master run id if this is a master */

// 從服務(wù)器的監(jiān)聽端口號

int slave_listening_port; /* As configured with: SLAVECONF listening-port */

// 最后被寫入的全局復(fù)制偏移量

long long woff; /* Last write global replication offset. */

} redisClient;

下面我們對上面三個(gè)部分一一解釋一下:

復(fù)制偏移量

執(zhí)行復(fù)制的雙方---主從服務(wù)器都會維護(hù)一個(gè)復(fù)制偏移量。

主服務(wù)器每次向從服務(wù)器傳播N個(gè)字節(jié)的數(shù)據(jù)時(shí),就將自己的復(fù)制偏移量的值加上N。

從服務(wù)器每次接收到主服務(wù)器傳播來的N個(gè)字節(jié)的數(shù)據(jù)時(shí),就將自己的復(fù)制偏移量加上N。

通過對比主從服務(wù)器的復(fù)制偏移量,程序很容易知道主從服務(wù)器是否處于一致狀態(tài)。

主從狀態(tài)一致:

主從狀態(tài)不一致:

假如從服務(wù)器A在斷線后就立即重新連接主服務(wù)器,并且成功,那么接下來,從服務(wù)器將向主服務(wù)器發(fā)送PSYNC命令,報(bào)告從服務(wù)器A當(dāng)前的復(fù)制偏移量為10086,那么這時(shí),主服務(wù)器應(yīng)該對從服務(wù)器執(zhí)行完全重同步還是部分重同步?如果執(zhí)行部分重同步的話,主服務(wù)器又如何補(bǔ)償從服務(wù)器A在斷線期間丟失的那部分?jǐn)?shù)據(jù)呢?

復(fù)制積壓區(qū)

復(fù)制積壓區(qū)是由主服務(wù)器維護(hù)的一個(gè)固定長度的隊(duì)列,默認(rèn)大小為1M。

當(dāng)主服務(wù)器進(jìn)行命令傳播時(shí),它不僅將寫命令發(fā)送給所有從服務(wù)器,還會將寫命令入列到復(fù)制積壓區(qū)緩沖區(qū)里面。如下圖:

因此,主服務(wù)器的復(fù)制積壓區(qū)里面會保存著一部分最近傳播的寫命令,并且復(fù)制積壓緩沖區(qū)會為隊(duì)列中的每個(gè)字節(jié)記錄相應(yīng)的復(fù)制偏移量。

當(dāng)從服務(wù)器重新連上主服務(wù)器時(shí),從服務(wù)器會通過PSYNC命令將自己的復(fù)制偏移量offset發(fā)送給主服務(wù)器,主服務(wù)器會根據(jù)這個(gè)復(fù)制偏移量來決定對主服務(wù)器進(jìn)行何種復(fù)制操作:

如果offset偏移量之后的數(shù)據(jù),仍然存在于復(fù)制積壓區(qū)里面,那么主服務(wù)器將對從服務(wù)器執(zhí)行部分重同步操作。

如果offset偏移量之后的數(shù)據(jù),不在復(fù)制積壓區(qū)里面,那么主服務(wù)器將會對從服務(wù)器進(jìn)行完全重同步操作。

服務(wù)器允許ID

每個(gè)Redis服務(wù)器,不論是主服務(wù)器還是從服務(wù)器都會有自己的運(yùn)行ID。這個(gè)ID在服務(wù)器啟動(dòng)時(shí)自動(dòng)生成,由40個(gè)隨機(jī)十六進(jìn)制字符組成。

當(dāng)從服務(wù)器對主服務(wù)器進(jìn)行初次復(fù)制時(shí),主服務(wù)器會將自己的運(yùn)行ID傳送給從服務(wù)器,而從服務(wù)器會將這個(gè)運(yùn)行ID保存起來。

當(dāng)從服務(wù)器斷線并重連上一個(gè)主服務(wù)器時(shí),從服務(wù)器將向當(dāng)前連接的主服務(wù)器發(fā)送自己的之前保存的運(yùn)行ID:

如果ID一致,說明短線后重連的就是之前連接的服務(wù)器;

如果ID不一致,說明短信??重連的不是之前鏈接的服務(wù)器,那么主服務(wù)器將對從服務(wù)器進(jìn)行完整重同步操作。

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

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

  • 在Redis的持久化中曾提到,Redis高可用的方案包括持久化、主從復(fù)制(及讀寫分離)、哨兵和集群。其中持久化側(cè)重...
    不變甄心閱讀 1,590評論 0 5
  • 本篇就一下方面展開分析 如何使用主從復(fù)制? 主從復(fù)制的原理(重點(diǎn)是全量復(fù)制和部分復(fù)制、以及心跳機(jī)制) 實(shí)際應(yīng)用中需...
    lucode閱讀 1,069評論 0 5
  • 本文主要介紹Redis集群中主從服務(wù)器復(fù)制功能的實(shí)現(xiàn)。 在Redis中,用戶可以通過執(zhí)行SLAVEOF命令或設(shè)置s...
    wenmingxing閱讀 1,044評論 0 5
  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,316評論 2 89
  • 作為考研狗,,倒計(jì)時(shí)76天,,加油,今年一定要考上心儀的大學(xué)
    你不懂我的任性閱讀 265評論 0 1

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