Redis之主從復(fù)制

在Redis中,用戶可以通過執(zhí)行SLAVEOF命令或者設(shè)置slaveof選項(xiàng),讓一個(gè)服務(wù)去復(fù)制另外一個(gè)服務(wù)器。

image.png

舊版復(fù)制功能的實(shí)現(xiàn)

  • 同步(sync)

  • 命令傳播(command propagate)

同步

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

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

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

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

image.png

命令傳播

在同步操作執(zhí)行完畢之后,主從服務(wù)器兩者的數(shù)據(jù)庫將達(dá)到- -致狀態(tài),但這種一致并不 是一成不變的,每當(dāng)主服務(wù)器執(zhí)行客戶端發(fā)送的寫命令時(shí),主服務(wù)器的數(shù)據(jù)庫就有可能會被 修改,并導(dǎo)致主從服務(wù)器狀態(tài)不再一致。

image.png

舊版復(fù)制功能的缺陷

在Redis中,從服務(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ù)器。

    對于初次復(fù)制來說,舊版復(fù)制功能能夠很好地完成任務(wù),但對于斷線后重復(fù)制來說,舊 版復(fù)制功能雖然也能讓主從服務(wù)器重新回到-致狀態(tài),但效率卻非常低。

SYNC命令是一個(gè)非常耗費(fèi)資源的操作 每次執(zhí)行SYNC命令,主從服務(wù)器需要執(zhí)行以下動(dòng)作:

  1. 主服務(wù)器需要執(zhí)行BGSAVE命令來生成RDB文件,這個(gè)生成操作會耗費(fèi)主服務(wù) 器大量的CPU、內(nèi)存和磁盤I/O資源。

  2. 主服務(wù)器需要將自己生成的RDB文件發(fā)送給從服務(wù)器,這個(gè)發(fā)送操作會耗費(fèi)主 從服務(wù)器大量的網(wǎng)絡(luò)資源(帶寬和流量),并對主服務(wù)器響應(yīng)命令請求的時(shí)間產(chǎn)生影響。

  3. 接收到RDB文件的從服務(wù)器需要載入主服務(wù)器發(fā)來的RDB文件,并且在載入. 期間,從服務(wù)器會因?yàn)樽枞鴽]辦法處理命令請求。 因?yàn)镾YNC命令是一個(gè)如此耗費(fèi)資源的操作,所以Redis有必要保證在真正有需要 時(shí)才執(zhí)行SYNC命令。


新版復(fù)制功能的實(shí)現(xiàn)

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

PSYNC命令具有完整重同步( full resynchronization)部分重同步( partial resynchronization)

  • 其中完整重同步用于處理初次復(fù)制情況:完整重同步的執(zhí)行步驟和SYNC命令的執(zhí) 行步驟基本- -樣,它們都是通過讓主服務(wù)器創(chuàng)建并發(fā)送RDB文件,以及向從服務(wù)器 發(fā)送保存在緩沖區(qū)里面的寫命令來進(jìn)行同步。

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

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

情況。

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

image.png

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

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

  • 主服務(wù)器的復(fù)制偏移量( replication offset )和從服務(wù)器的復(fù)制偏移量。

  • 主服務(wù)器的復(fù)制積壓緩沖區(qū)( replication backlog )。

  • 服務(wù)器的運(yùn)行ID(runID)。

復(fù)制偏移量

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

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

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

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

復(fù)制積壓緩沖區(qū)是由主服務(wù)器維護(hù)的--個(gè)固定長度(fixed-size)先進(jìn)先出(FIFO)隊(duì)列,默認(rèn)大小為1MB。

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


image.png

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

主服務(wù)器向從服務(wù)器發(fā)送丟失的數(shù)據(jù)

根據(jù)需求調(diào)整復(fù)制積壓緩沖區(qū)的大小

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

除了復(fù)制偏移量和復(fù)制積壓緩沖區(qū)之外,實(shí)現(xiàn)部分重同步還需要用到服務(wù)器運(yùn)行ID(runID):

  • 每個(gè)Redis服務(wù)器,不論主服務(wù)器還是從服務(wù),都會有自己的運(yùn)行ID。
  • 運(yùn)行ID在服務(wù)器啟動(dòng)時(shí)自動(dòng)生成,由40個(gè)隨機(jī)的十六進(jìn)制字符組成,例如53b9b28df8042fdc9ab5e3f cbbbabf f1d5dce2b3。
  • 當(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:
  • 如果從服務(wù)器保存的運(yùn)行ID和當(dāng)前連接的主服務(wù)器的運(yùn)行ID相同,那么說明從服務(wù)器斷線之前復(fù)制的就是當(dāng)前連接的這個(gè)主服務(wù)器,主服務(wù)器可以繼續(xù)嘗試執(zhí)行部分重同步操作。
  • 相反地,如果從服務(wù)器保存的運(yùn)行ID和當(dāng)前連接的主服務(wù)器的運(yùn)行ID并不相同,那么說明從服務(wù)器斷線之前復(fù)制的主服務(wù)器并不是當(dāng)前連接的這個(gè)主服務(wù)器,主服務(wù)器將對從服務(wù)器執(zhí)行完整重同步操作。

PSYNC命令實(shí)現(xiàn)

PSYNC執(zhí)行完整重同步和部分重同步時(shí)可能遇上的情況

復(fù)制的實(shí)現(xiàn)

通過向從服務(wù)器發(fā)送SLAVEOF命令,我們可以讓-一個(gè)從服務(wù)器去復(fù)制- -個(gè)主服務(wù)器:SLAVEOF <master_ ip> <master_ _port>

1.設(shè)置主機(jī)的地址和端口
2.建立套字節(jié)連接


3.發(fā)送PING命令

  • 雖然主從服務(wù)器成功建立起了套接字連接,但雙方并未使用該套接字進(jìn)行過任何通信,通過發(fā)送PING命令可以檢查套接字的讀寫狀態(tài)是否正常。
  • 因?yàn)閺?fù)制工作接下來的幾個(gè)步驟都必須在主服務(wù)器可以正常處理命令請求的狀態(tài)下才能進(jìn)行,通過發(fā)送PING命令可以檢查主服務(wù)器能否正常處理命令請求。



4.身份驗(yàn)證
5.發(fā)送端口信息

  • 在身份驗(yàn)證步驟之后,從服務(wù)器將執(zhí)行命令REPLCONE listening-port <port-number>,向主服務(wù)器發(fā)送從服務(wù)器的監(jiān)聽端口號。

6.同步
7.命令傳播

心跳檢測

在命令傳播階段,從服務(wù)器默認(rèn)會以每秒- - 次的頻率,向主服務(wù)器發(fā)送命令:
REPLCONF ACK <rep1 ication_ offset>
其中replication_ offset 是從服務(wù)器當(dāng)前的復(fù)制偏移量。
發(fā)送REPLCONP ACK命令對于主從服務(wù)器有三個(gè)作用: .

  • 檢測主從服務(wù)器的網(wǎng)絡(luò)連接狀態(tài)。
  • 輔助實(shí)現(xiàn)min-slaves選項(xiàng)。

Redis的min-slaves-to-write和min-slaves-max- lag兩個(gè)選項(xiàng)可以防止主服
務(wù)器在不安全的情況下執(zhí)行寫命令。
舉個(gè)例子,如果我們向主服務(wù)器提供以下設(shè)置:
min-slaves-to-write 3
min-slaves-max-lag 10
那么在從服務(wù)器的數(shù)量少于3個(gè),或者三個(gè)從服務(wù)器的延遲(lag) 值都大于或等于10秒時(shí),主服務(wù)器將拒絕執(zhí)行寫命令,這里的延遲值就是上面提到的INFOreplication命令的lag值。

  • 檢測命令丟失。
    如果因?yàn)榫W(wǎng)絡(luò)故障,主服務(wù)器傳播給從服務(wù)器的寫命令在半路丟失,那么當(dāng)從服務(wù)器向主服務(wù)器發(fā)送REPLCONF ACK命令時(shí),主服務(wù)器將發(fā)覺從服務(wù)器當(dāng)前的復(fù)制偏移量少于自已的復(fù)制偏移量,然后主服務(wù)器就會根據(jù)從服務(wù)器提交的復(fù)制偏移量,在復(fù)制積壓緩沖區(qū)里面找到從服務(wù)器缺少的數(shù)據(jù),并將這些數(shù)據(jù)重新發(fā)送給從服務(wù)器。

參考書籍:《Redis設(shè)計(jì)與實(shí)現(xià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ù)。

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