精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

深入學(xué)習(xí)Redis高可用的基石:主從復(fù)制

開發(fā) 架構(gòu) 開發(fā)工具 Redis
在前面的兩篇文章中,分別介紹了 Redis 的內(nèi)存模型和 Redis 的持久化,今天我們來深入學(xué)習(xí) Redis 的主從復(fù)制。

在前面的兩篇文章中,分別介紹了 Redis 的內(nèi)存模型和 Redis 的持久化,今天我們來深入學(xué)習(xí) Redis 的主從復(fù)制。

[[235515]]

在 Redis 的持久化中曾提到,Redis 高可用的方案包括持久化、主從復(fù)制(及讀寫分離)、哨兵和集群。

其中持久化側(cè)重解決的是 Redis 數(shù)據(jù)的單機備份問題(從內(nèi)存到硬盤的備份);而主從復(fù)制則側(cè)重解決數(shù)據(jù)的多機熱備。此外,主從復(fù)制還可以實現(xiàn)負載均衡和故障恢復(fù)。

我將從以下幾個部分詳細介紹 Redis 主從復(fù)制的方方面面:

  • 主從復(fù)制概述
  • 如何使用主從復(fù)制
  • 主從復(fù)制的實現(xiàn)原理
  • 應(yīng)用中的問題
  • 總結(jié)

主從復(fù)制概述

主從復(fù)制,是指將一臺 Redis 服務(wù)器的數(shù)據(jù),復(fù)制到其他的 Redis 服務(wù)器。前者稱為主節(jié)點(master),后者稱為從節(jié)點(slave);數(shù)據(jù)的復(fù)制是單向的,只能由主節(jié)點到從節(jié)點。

默認情況下,每臺 Redis 服務(wù)器都是主節(jié)點;且一個主節(jié)點可以有多個從節(jié)點(或沒有從節(jié)點),但一個從節(jié)點只能有一個主節(jié)點。

主從復(fù)制的作用主要包括:

  • 數(shù)據(jù)冗余:主從復(fù)制實現(xiàn)了數(shù)據(jù)的熱備份,是持久化之外的一種數(shù)據(jù)冗余方式。
  • 故障恢復(fù):當(dāng)主節(jié)點出現(xiàn)問題時,可以由從節(jié)點提供服務(wù),實現(xiàn)快速的故障恢復(fù);實際上是一種服務(wù)的冗余。
  • 負載均衡:在主從復(fù)制的基礎(chǔ)上,配合讀寫分離,可以由主節(jié)點提供寫服務(wù),由從節(jié)點提供讀服務(wù)(即寫 Redis 數(shù)據(jù)時應(yīng)用連接主節(jié)點,讀 Redis 數(shù)據(jù)時應(yīng)用連接從節(jié)點),分擔(dān)服務(wù)器負載;尤其是在寫少讀多的場景下,通過多個從節(jié)點分擔(dān)讀負載,可以大大提高 Redis 服務(wù)器的并發(fā)量。
  • 高可用基石:除了上述作用以外,主從復(fù)制還是哨兵和集群能夠?qū)嵤┑幕A(chǔ),因此說主從復(fù)制是 Redis 高可用的基礎(chǔ)。

如何使用主從復(fù)制

為了更直觀的理解主從復(fù)制,在介紹其內(nèi)部原理之前,先說明我們需要如何操作才能開啟主從復(fù)制。

建立復(fù)制

需要注意,主從復(fù)制的開啟,完全是在從節(jié)點發(fā)起的;不需要我們在主節(jié)點做任何事情。

從節(jié)點開啟主從復(fù)制,有 3 種方式:

  • 在從服務(wù)器的配置文件中加入:slaveof <masterip> <masterport>。
  • redis-server 啟動命令后加入 --slaveof <masterip> <masterport>。
  • Redis 服務(wù)器啟動后,直接通過客戶端執(zhí)行命令:slaveof <masterip> <masterport>,則該 Redis 實例成為從節(jié)點。

上述 3 種方式是等效的,下面以客戶端命令的方式為例,看一下當(dāng)執(zhí)行了 slaveof 后,Redis 主節(jié)點和從節(jié)點的變化。

實例

準(zhǔn)備工作:啟動兩個節(jié)點。為了方便起見,實驗所使用的主從節(jié)點是在一臺機器上的不同 Redis 實例。

其中主節(jié)點監(jiān)聽 6379 端口,從節(jié)點監(jiān)聽 6380 端口;從節(jié)點監(jiān)聽的端口號可以在配置文件中修改:

啟動后可以看到:

兩個 Redis 節(jié)點啟動后(分別稱為6379節(jié)點和6380節(jié)點),默認都是主節(jié)點。

建立復(fù)制:此時在 6380 節(jié)點執(zhí)行 slaveof 命令,使之變?yōu)閺墓?jié)點。

觀察效果:下面驗證一下,在主從復(fù)制建立后,主節(jié)點的數(shù)據(jù)會復(fù)制到從節(jié)點中。

首先在從節(jié)點查詢一個不存在的 key:

然后在主節(jié)點中增加這個 key:

此時在從節(jié)點中再次查詢這個 key,會發(fā)現(xiàn)主節(jié)點的操作已經(jīng)同步至從節(jié)點:

然后在主節(jié)點刪除這個 key:

此時在從節(jié)點中再次查詢這個 key,會發(fā)現(xiàn)主節(jié)點的操作已經(jīng)同步至從節(jié)點:

斷開復(fù)制

通過 slaveof <masterip> <masterport> 命令建立主從復(fù)制關(guān)系以后,可以通過 slaveof no one 斷開。

需要注意的是,從節(jié)點斷開復(fù)制后,不會刪除已有的數(shù)據(jù),只是不再接受主節(jié)點新的數(shù)據(jù)變化。

從節(jié)點執(zhí)行 slaveof no one 后,打印日志如下圖所示;可以看出斷開復(fù)制后,從節(jié)點又變回為主節(jié)點。

主節(jié)點打印日志如下:

主從復(fù)制的實現(xiàn)原理

上面一節(jié)中,我們介紹了如何操作可以建立主從關(guān)系;本小節(jié)將介紹主從復(fù)制的實現(xiàn)原理。

主從復(fù)制過程大體可以分為 3 個階段:

  • 連接建立階段(即準(zhǔn)備階段)
  • 數(shù)據(jù)同步階段
  • 命令傳播階段

連接建立階段

該階段的主要作用是在主從節(jié)點之間建立連接,為數(shù)據(jù)同步做好準(zhǔn)備。

步驟 1:保存主節(jié)點信息

從節(jié)點服務(wù)器內(nèi)部維護了兩個字段,即 masterhost 和 masterport 字段,用于存儲主節(jié)點的 ip 和 port 信息。

需要注意的是,slaveof 是異步命令,從節(jié)點完成主節(jié)點 ip 和 port 的保存后,向發(fā)送 slaveof 命令的客戶端直接返回 OK,實際的復(fù)制操作在這之后才開始進行。

這個過程中,可以看到從節(jié)點打印日志如下:

步驟 2:建立 Socket 連接

從節(jié)點每秒 1 次調(diào)用復(fù)制定時函數(shù) replicationCron(),如果發(fā)現(xiàn)了有主節(jié)點可以連接,便會根據(jù)主節(jié)點的 ip 和 port,創(chuàng)建 socket 連接。

如果連接成功,則:

  • 從節(jié)點:為該 socket 建立一個專門處理復(fù)制工作的文件事件處理器,負責(zé)后續(xù)的復(fù)制工作,如接收 RDB 文件、接收命令傳播等。
  • 主節(jié)點:接收到從節(jié)點的 socket 連接后(即 accept 之后),為該 socket 創(chuàng)建相應(yīng)的客戶端狀態(tài),并將從節(jié)點看做是連接到主節(jié)點的一個客戶端,后面的步驟會以從節(jié)點向主節(jié)點發(fā)送命令請求的形式來進行。

這個過程中,從節(jié)點打印日志如下:

步驟 3:發(fā)送 Ping 命令

從節(jié)點成為主節(jié)點的客戶端之后,發(fā)送 ping 命令進行***請求,目的是:檢查 socket 連接是否可用,以及主節(jié)點當(dāng)前是否能夠處理請求。

從節(jié)點發(fā)送 ping 命令后,可能出現(xiàn) 3 種情況:

  • 返回pong:說明 socket 連接正常,且主節(jié)點當(dāng)前可以處理請求,復(fù)制過程繼續(xù)。
  • 超時:一定時間后從節(jié)點仍未收到主節(jié)點的回復(fù),說明 socket 連接不可用,則從節(jié)點斷開 socket 連接,并重連。
  • 返回 pong 以外的結(jié)果:如果主節(jié)點返回其他結(jié)果,如正在處理超時運行的腳本,說明主節(jié)點當(dāng)前無法處理命令,則從節(jié)點斷開 socket 連接,并重連。

在主節(jié)點返回 pong 情況下,從節(jié)點打印日志如下:

步驟 4:身份驗證

如果從節(jié)點中設(shè)置了 masterauth 選項,則從節(jié)點需要向主節(jié)點進行身份驗證;沒有設(shè)置該選項,則不需要驗證。

從節(jié)點進行身份驗證是通過向主節(jié)點發(fā)送 auth 命令進行的,auth 命令的參數(shù)即為配置文件中的 masterauth 的值。

如果主節(jié)點設(shè)置密碼的狀態(tài),與從節(jié)點 masterauth 的狀態(tài)一致(一致是指都存在,且密碼相同,或者都不存在),則身份驗證通過,復(fù)制過程繼續(xù);如果不一致,則從節(jié)點斷開 socket 連接,并重連。

步驟 5:發(fā)送從節(jié)點端口信息

身份驗證之后,從節(jié)點會向主節(jié)點發(fā)送其監(jiān)聽的端口號(前述例子中為 6380),主節(jié)點將該信息保存到該從節(jié)點對應(yīng)的客戶端的 slave_listening_port 字段中。

該端口信息除了在主節(jié)點中執(zhí)行 info Replication 時顯示以外,沒有其他作用。

數(shù)據(jù)同步階段

主從節(jié)點之間的連接建立以后,便可以開始進行數(shù)據(jù)同步,該階段可以理解為從節(jié)點數(shù)據(jù)的初始化。

具體執(zhí)行的方式是:從節(jié)點向主節(jié)點發(fā)送 psync 命令(Redis 2.8 以前是 sync 命令),開始同步。

數(shù)據(jù)同步階段是主從復(fù)制最核心的階段,根據(jù)主從節(jié)點當(dāng)前狀態(tài)的不同,可以分為全量復(fù)制和部分復(fù)制。

需要注意的是,在數(shù)據(jù)同步階段之前,從節(jié)點是主節(jié)點的客戶端,主節(jié)點不是從節(jié)點的客戶端;而到了這一階段及以后,主從節(jié)點互為客戶端。

原因在于:在此之前,主節(jié)點只需要響應(yīng)從節(jié)點的請求即可,不需要主動發(fā)請求,而在數(shù)據(jù)同步階段和后面的命令傳播階段,主節(jié)點需要主動向從節(jié)點發(fā)送請求(如推送緩沖區(qū)中的寫命令),才能完成復(fù)制。

命令傳播階段

數(shù)據(jù)同步階段完成后,主從節(jié)點進入命令傳播階段;在這個階段主節(jié)點將自己執(zhí)行的寫命令發(fā)送給從節(jié)點,從節(jié)點接收命令并執(zhí)行,從而保證主從節(jié)點數(shù)據(jù)的一致性。

在命令傳播階段,除了發(fā)送寫命令,主從節(jié)點還維持著心跳機制:PING 和 REPLCONF ACK。

由于心跳機制的原理涉及部分復(fù)制,因此將在介紹了部分復(fù)制的相關(guān)內(nèi)容后單獨介紹該心跳機制。

延遲與不一致:需要注意的是,命令傳播是異步的過程,即主節(jié)點發(fā)送寫命令后并不會等待從節(jié)點的回復(fù);因此實際上主從節(jié)點之間很難保持實時的一致性,延遲在所難免。

數(shù)據(jù)不一致的程度,與主從節(jié)點之間的網(wǎng)絡(luò)狀況、主節(jié)點寫命令的執(zhí)行頻率、以及主節(jié)點中的 repl-disable-tcp-nodelay 配置等有關(guān)。

repl-disable-tcp-nodelay no:該配置作用于命令傳播階段,控制主節(jié)點是否禁止與從節(jié)點的 TCP_NODELAY;默認 no,即不禁止 TCP_NODELAY。

當(dāng)設(shè)置為 yes 時,TCP 會對包進行合并從而減少帶寬,但是發(fā)送的頻率會降低,從節(jié)點數(shù)據(jù)延遲增加,一致性變差;具體發(fā)送頻率與 Linux 內(nèi)核的配置有關(guān),默認配置為 40ms。

當(dāng)設(shè)置為 no 時,TCP 會立馬將主節(jié)點的數(shù)據(jù)發(fā)送給從節(jié)點,帶寬增加但延遲變小。

一般來說,只有當(dāng)應(yīng)用對 Redis 數(shù)據(jù)不一致的容忍度較高,且主從節(jié)點之間網(wǎng)絡(luò)狀況不好時,才會設(shè)置為 yes;多數(shù)情況使用默認值 no。

數(shù)據(jù)同步階段:全量復(fù)制和部分復(fù)制

在 Redis 2.8 以前,從節(jié)點向主節(jié)點發(fā)送 sync 命令請求同步數(shù)據(jù),此時的同步方式是全量復(fù)制。

在 Redis 2.8 及以后,從節(jié)點可以發(fā)送 psync 命令請求同步數(shù)據(jù),此時根據(jù)主從節(jié)點當(dāng)前狀態(tài)的不同,同步方式可能是全量復(fù)制或部分復(fù)制。后文介紹以 Redis 2.8 及以后版本為例。

全量復(fù)制:用于初次復(fù)制或其他無法進行部分復(fù)制的情況,將主節(jié)點中的所有數(shù)據(jù)都發(fā)送給從節(jié)點,是一個非常重型的操作。

部分復(fù)制:用于網(wǎng)絡(luò)中斷等情況后的復(fù)制,只將中斷期間主節(jié)點執(zhí)行的寫命令發(fā)送給從節(jié)點,與全量復(fù)制相比更加高效。

需要注意的是,如果網(wǎng)絡(luò)中斷時間過長,導(dǎo)致主節(jié)點沒有能夠完整地保存中斷期間執(zhí)行的寫命令,則無法進行部分復(fù)制,仍使用全量復(fù)制。

全量復(fù)制

Redis 通過 psync 命令進行全量復(fù)制的過程如下:

  • 從節(jié)點判斷無法進行部分復(fù)制,向主節(jié)點發(fā)送全量復(fù)制的請求;或從節(jié)點發(fā)送部分復(fù)制的請求,但主節(jié)點判斷無法進行全量復(fù)制;具體判斷過程需要在講述了部分復(fù)制原理后再介紹。
  • 主節(jié)點收到全量復(fù)制的命令后,執(zhí)行 bgsave,在后臺生成 RDB 文件,并使用一個緩沖區(qū)(稱為復(fù)制緩沖區(qū))記錄從現(xiàn)在開始執(zhí)行的所有寫命令
  • 主節(jié)點的 bgsave 執(zhí)行完成后,將 RDB 文件發(fā)送給從節(jié)點;從節(jié)點首先清除自己的舊數(shù)據(jù),然后載入接收的 RDB 文件,將數(shù)據(jù)庫狀態(tài)更新至主節(jié)點執(zhí)行 bgsave 時的數(shù)據(jù)庫狀態(tài)。
  • 主節(jié)點將前述復(fù)制緩沖區(qū)中的所有寫命令發(fā)送給從節(jié)點,從節(jié)點執(zhí)行這些寫命令,將數(shù)據(jù)庫狀態(tài)更新至主節(jié)點的***狀態(tài)
  • 如果從節(jié)點開啟了 AOF,則會觸發(fā) bgrewriteaof 的執(zhí)行,從而保證 AOF 文件更新至主節(jié)點的***狀態(tài)。

下面是執(zhí)行全量復(fù)制時,主從節(jié)點打印的日志;可以看出日志內(nèi)容與上述步驟是完全對應(yīng)的。

主節(jié)點的打印日志如下:

從節(jié)點打印日志如下圖所示:

其中,有幾點需要注意:

  • 從節(jié)點接收了來自主節(jié)點的 89260 個字節(jié)的數(shù)據(jù)。
  • 從節(jié)點在載入主節(jié)點的數(shù)據(jù)之前要先將老數(shù)據(jù)清除。
  • 從節(jié)點在同步完數(shù)據(jù)后,調(diào)用了 bgrewriteaof。

通過全量復(fù)制的過程可以看出,全量復(fù)制是非常重型的操作:

  • 主節(jié)點通過 bgsave 命令 fork 子進程進行 RDB 持久化,該過程是非常消耗 CPU、內(nèi)存(頁表復(fù)制)、硬盤 IO 的;關(guān)于 bgsave 的性能問題,可以參考深入學(xué)習(xí)Redis(2):持久化。
  • 主節(jié)點通過網(wǎng)絡(luò)將 RDB 文件發(fā)送給從節(jié)點,對主從節(jié)點的帶寬都會帶來很大的消耗。
  • 從節(jié)點清空老數(shù)據(jù)、載入新 RDB 文件的過程是阻塞的,無法響應(yīng)客戶端的命令;如果從節(jié)點執(zhí)行 bgrewriteaof,也會帶來額外的消耗。

部分復(fù)制

由于全量復(fù)制在主節(jié)點數(shù)據(jù)量較大時效率太低,因此 Redis 2.8 開始提供部分復(fù)制,用于處理網(wǎng)絡(luò)中斷時的數(shù)據(jù)同步。

部分復(fù)制的實現(xiàn),依賴于三個重要的概念:

復(fù)制偏移量:主節(jié)點和從節(jié)點分別維護一個復(fù)制偏移量(offset),代表的是主節(jié)點向從節(jié)點傳遞的字節(jié)數(shù)。

主節(jié)點每次向從節(jié)點傳播 N 個字節(jié)數(shù)據(jù)時,主節(jié)點的 offset 增加 N;從節(jié)點每次收到主節(jié)點傳來的 N 個字節(jié)數(shù)據(jù)時,從節(jié)點的 offset 增加 N。

offset 用于判斷主從節(jié)點的數(shù)據(jù)庫狀態(tài)是否一致:如果二者 offset 相同,則一致;如果 offset 不同,則不一致,此時可以根據(jù)兩個 offset 找出從節(jié)點缺少的那部分數(shù)據(jù)。

例如,如果主節(jié)點的 offset 是 1000,而從節(jié)點的 offset 是 500,那么部分復(fù)制就需要將 offset 為 501-1000 的數(shù)據(jù)傳遞給從節(jié)點。

而 offset 為 501-1000 的數(shù)據(jù)存儲的位置,就是下面要介紹的復(fù)制積壓緩沖區(qū)。

復(fù)制積壓緩沖區(qū):復(fù)制積壓緩沖區(qū)是由主節(jié)點維護的、固定長度的、先進先出(FIFO)隊列,默認大小 1MB。

當(dāng)主節(jié)點開始有從節(jié)點時創(chuàng)建,其作用是備份主節(jié)點最近發(fā)送給從節(jié)點的數(shù)據(jù)。注意,無論主節(jié)點有一個還是多個從節(jié)點,都只需要一個復(fù)制積壓緩沖區(qū)。

在命令傳播階段,主節(jié)點除了將寫命令發(fā)送給從節(jié)點,還會發(fā)送一份給復(fù)制積壓緩沖區(qū),作為寫命令的備份;除了存儲寫命令,復(fù)制積壓緩沖區(qū)中還存儲了其中的每個字節(jié)對應(yīng)的復(fù)制偏移量(offset)。

由于復(fù)制積壓緩沖區(qū)定長且是先進先出,所以它保存的是主節(jié)點最近執(zhí)行的寫命令;時間較早的寫命令會被擠出緩沖區(qū)。

由于該緩沖區(qū)長度固定且有限,因此可以備份的寫命令也有限,當(dāng)主從節(jié)點 offset 的差距過大超過緩沖區(qū)長度時,將無法執(zhí)行部分復(fù)制,只能執(zhí)行全量復(fù)制。

反過來說,為了提高網(wǎng)絡(luò)中斷時部分復(fù)制執(zhí)行的概率,可以根據(jù)需要增大復(fù)制積壓緩沖區(qū)的大小(通過配置repl-backlog-size)。

例如如果網(wǎng)絡(luò)中斷的平均時間是 60s,而主節(jié)點平均每秒產(chǎn)生的寫命令(特定協(xié)議格式)所占的字節(jié)數(shù)為 100KB,則復(fù)制積壓緩沖區(qū)的平均需求為 6MB。

保險起見,可以設(shè)置為 12MB,來保證絕大多數(shù)斷線情況都可以使用部分復(fù)制。

從節(jié)點將 offset 發(fā)送給主節(jié)點后,主節(jié)點根據(jù) offset 和緩沖區(qū)大小決定能否執(zhí)行部分復(fù)制:

  • 如果 offset 偏移量之后的數(shù)據(jù),仍然都在復(fù)制積壓緩沖區(qū)里,則執(zhí)行部分復(fù)制。
  • 如果 offset 偏移量之后的數(shù)據(jù)已不在復(fù)制積壓緩沖區(qū)中(數(shù)據(jù)已被擠出),則執(zhí)行全量復(fù)制。

服務(wù)器運行 ID(runid):每個 Redis 節(jié)點(無論主從),在啟動時都會自動生成一個隨機 ID(每次啟動都不一樣),由 40 個隨機的十六進制字符組成;runid 用來唯一識別一個 Redis 節(jié)點。

通過 info Server 命令,可以查看節(jié)點的 runid:

主從節(jié)點初次復(fù)制時,主節(jié)點將自己的 runid 發(fā)送給從節(jié)點,從節(jié)點將這個 runid 保存起來;當(dāng)斷線重連時,從節(jié)點會將這個 runid 發(fā)送給主節(jié)點。

主節(jié)點根據(jù) runid 判斷能否進行部分復(fù)制:

  • 如果從節(jié)點保存的 runid 與主節(jié)點現(xiàn)在的 runid 相同,說明主從節(jié)點之前同步過,主節(jié)點會繼續(xù)嘗試使用部分復(fù)制(到底能不能部分復(fù)制還要看 offset 和復(fù)制積壓緩沖區(qū)的情況)。
  • 如果從節(jié)點保存的 runid 與主節(jié)點現(xiàn)在的 runid 不同,說明從節(jié)點在斷線前同步的 Redis 節(jié)點并不是當(dāng)前的主節(jié)點,只能進行全量復(fù)制。

psync 命令的執(zhí)行:在了解了復(fù)制偏移量、復(fù)制積壓緩沖區(qū)、節(jié)點運行 id 之后,本節(jié)將介紹 psync 命令的參數(shù)和返回值,從而說明 psync 命令執(zhí)行過程中,主從節(jié)點是如何確定使用全量復(fù)制還是部分復(fù)制的。

psync 命令的執(zhí)行過程可以參見下圖:

首先,從節(jié)點根據(jù)當(dāng)前狀態(tài),決定如何調(diào)用 psync 命令:

  • 如果從節(jié)點之前未執(zhí)行過 slaveof 或最近執(zhí)行了 slaveof no one,則從節(jié)點發(fā)送命令為 psync ? -1,向主節(jié)點請求全量復(fù)制。
  • 如果從節(jié)點之前執(zhí)行了 slaveof,則發(fā)送命令為 psync <runid> <offset>,其中 runid 為上次復(fù)制的主節(jié)點的 runid,offset 為上次復(fù)制截止時從節(jié)點保存的復(fù)制偏移量。

主節(jié)點根據(jù)收到的psync命令,及當(dāng)前服務(wù)器狀態(tài),決定執(zhí)行全量復(fù)制還是部分復(fù)制:

  • 如果主節(jié)點版本低于 Redis 2.8,則返回 -ERR 回復(fù),此時從節(jié)點重新發(fā)送 sync 命令執(zhí)行全量復(fù)制。
  • 如果主節(jié)點版本夠新,且 runid 與從節(jié)點發(fā)送的 runid 相同,且從節(jié)點發(fā)送的 offset 之后的數(shù)據(jù)在復(fù)制積壓緩沖區(qū)中都存在,則回復(fù) +CONTINUE,表示將進行部分復(fù)制,從節(jié)點等待主節(jié)點發(fā)送其缺少的數(shù)據(jù)即可。
  • 如果主節(jié)點版本夠新,但是 runid 與從節(jié)點發(fā)送的 runid 不同,或從節(jié)點發(fā)送的 offset 之后的數(shù)據(jù)已不在復(fù)制積壓緩沖區(qū)中(在隊列中被擠出了),則回復(fù) +FULLRESYNC <runid> <offset>,表示要進行全量復(fù)制。

其中 runid 表示主節(jié)點當(dāng)前的 runid,offset 表示主節(jié)點當(dāng)前的 offset,從節(jié)點保存這兩個值,以備使用。

部分復(fù)制演示:在下面的演示中,網(wǎng)絡(luò)中斷幾分鐘后恢復(fù),斷開連接的主從節(jié)點進行了部分復(fù)制;為了便于模擬網(wǎng)絡(luò)中斷,本例中的主從節(jié)點在局域網(wǎng)中的兩臺機器上。

網(wǎng)絡(luò)中斷一段時間后,主節(jié)點和從節(jié)點都會發(fā)現(xiàn)失去了與對方的連接(關(guān)于主從節(jié)點對超時的判斷機制,后面會有說明)。

此后,從節(jié)點便開始執(zhí)行對主節(jié)點的重連,由于此時網(wǎng)絡(luò)還沒有恢復(fù),重連失敗,從節(jié)點會一直嘗試重連。

主節(jié)點日志如下:

從節(jié)點日志如下:

網(wǎng)絡(luò)恢復(fù)后,從節(jié)點連接主節(jié)點成功,并請求進行部分復(fù)制,主節(jié)點接收請求后,二者進行部分復(fù)制以同步數(shù)據(jù)。

主節(jié)點日志如下:

從節(jié)點日志如下:

命令傳播階段:心跳機制

在命令傳播階段,除了發(fā)送寫命令,主從節(jié)點還維持著心跳機制:PING 和 REPLCONF ACK。心跳機制對于主從復(fù)制的超時判斷、數(shù)據(jù)安全等有作用。

主->從:PING

每隔指定的時間,主節(jié)點會向從節(jié)點發(fā)送 PING 命令,這個 PING 命令的作用,主要是為了讓從節(jié)點進行超時判斷。

PING 發(fā)送的頻率由 repl-ping-slave-period 參數(shù)控制,單位是秒,默認值是 10s。

關(guān)于該 PING 命令究竟是由主節(jié)點發(fā)給從節(jié)點,還是相反,有一些爭議;因為在 Redis 的官方文檔中,對該參數(shù)的注釋中說明是從節(jié)點向主節(jié)點發(fā)送 PING 命令,如下圖所示:

但是根據(jù)該參數(shù)的名稱(含有 ping-slave),以及代碼實現(xiàn),我認為該 PING 命令是主節(jié)點發(fā)給從節(jié)點的。

相關(guān)代碼如下:

從->主:REPLCONF ACK

在命令傳播階段,從節(jié)點會向主節(jié)點發(fā)送 REPLCONF ACK 命令,頻率是每秒 1 次;命令格式為:REPLCONF ACK {offset},其中 offset 指從節(jié)點保存的復(fù)制偏移量。

REPLCONF ACK 命令的作用包括:

實時監(jiān)測主從節(jié)點網(wǎng)絡(luò)狀態(tài):該命令會被主節(jié)點用于復(fù)制超時的判斷。此外,在主節(jié)點中使用 info Replication,可以看到其從節(jié)點的狀態(tài)中的 lag 值,代表的是主節(jié)點上次收到該 REPLCONF ACK 命令的時間間隔。

在正常情況下,該值應(yīng)該是 0 或 1,如下圖所示:

檢測命令丟失:從節(jié)點發(fā)送了自身的 offset,主節(jié)點會與自己的 offset 對比,如果從節(jié)點數(shù)據(jù)缺失(如網(wǎng)絡(luò)丟包),主節(jié)點會推送缺失的數(shù)據(jù)(這里也會利用復(fù)制積壓緩沖區(qū))。

注意,offset 和復(fù)制積壓緩沖區(qū),不僅可以用于部分復(fù)制,也可以用于處理命令丟失等情形;區(qū)別在于前者是在斷線重連后進行的,而后者是在主從節(jié)點沒有斷線的情況下進行的。

輔助保證從節(jié)點的數(shù)量和延遲:Redis 主節(jié)點中使用 min-slaves-to-write 和 min-slaves-max-lag 參數(shù),來保證主節(jié)點在不安全的情況下不會執(zhí)行寫命令;所謂不安全,是指從節(jié)點數(shù)量太少,或延遲過高。

例如 min-slaves-to-write 和 min-slaves-max-lag 分別是 3 和 10,含義是如果從節(jié)點數(shù)量小于 3 個,或所有從節(jié)點的延遲值都大于 10s,則主節(jié)點拒絕執(zhí)行寫命令。

而這里從節(jié)點延遲值的獲取,就是通過主節(jié)點接收到 REPLCONF ACK 命令的時間來判斷的,即前面所說的 info Replication 中的 lag 值。

應(yīng)用中的問題

讀寫分離及其中的問題

在主從復(fù)制基礎(chǔ)上實現(xiàn)的讀寫分離,可以實現(xiàn) Redis 的讀負載均衡。

由主節(jié)點提供寫服務(wù),由一個或多個從節(jié)點提供讀服務(wù)(多個從節(jié)點既可以提高數(shù)據(jù)冗余程度,也可以***化讀負載能力);在讀負載較大的應(yīng)用場景下,可以大大提高 Redis 服務(wù)器的并發(fā)量。

下面介紹在使用 Redis 讀寫分離時,需要注意的問題。

延遲與不一致問題

前面已經(jīng)講到,由于主從復(fù)制的命令傳播是異步的,延遲與數(shù)據(jù)的不一致不可避免。

如果應(yīng)用對數(shù)據(jù)不一致的接受程度程度較低,可能的優(yōu)化措施包括:

  • 優(yōu)化主從節(jié)點之間的網(wǎng)絡(luò)環(huán)境(如在同機房部署)。
  • 監(jiān)控主從節(jié)點延遲(通過 offset)判斷,如果從節(jié)點延遲過大,通知應(yīng)用不再通過該從節(jié)點讀取數(shù)據(jù)。
  • 使用集群同時擴展寫負載和讀負載等。

在命令傳播階段以外的其他情況下,從節(jié)點的數(shù)據(jù)不一致可能更加嚴重,例如連接在數(shù)據(jù)同步階段,或從節(jié)點失去與主節(jié)點的連接時等。

從節(jié)點的 slave-serve-stale-data 參數(shù)便與此有關(guān):它控制這種情況下從節(jié)點的表現(xiàn);如果為 yes(默認值),則從節(jié)點仍能夠響應(yīng)客戶端的命令,如果為 no,則從節(jié)點只能響應(yīng) info、slaveof 等少數(shù)命令。

該參數(shù)的設(shè)置與應(yīng)用對數(shù)據(jù)一致性的要求有關(guān);如果對數(shù)據(jù)一致性要求很高,則應(yīng)設(shè)置為 no。

數(shù)據(jù)過期問題

在單機版 Redis 中,存在兩種刪除策略:

  • 惰性刪除:服務(wù)器不會主動刪除數(shù)據(jù),只有當(dāng)客戶端查詢某個數(shù)據(jù)時,服務(wù)器判斷該數(shù)據(jù)是否過期,如果過期則刪除。
  • 定期刪除:服務(wù)器執(zhí)行定時任務(wù)刪除過期數(shù)據(jù),但是考慮到內(nèi)存和 CPU 的折中(刪除會釋放內(nèi)存,但是頻繁的刪除操作對 CPU 不友好),該刪除的頻率和執(zhí)行時間都受到了限制。

在主從復(fù)制場景下,為了主從節(jié)點的數(shù)據(jù)一致性,從節(jié)點不會主動刪除數(shù)據(jù),而是由主節(jié)點控制從節(jié)點中過期數(shù)據(jù)的刪除。

由于主節(jié)點的惰性刪除和定期刪除策略,都不能保證主節(jié)點及時對過期數(shù)據(jù)執(zhí)行刪除操作,因此,當(dāng)客戶端通過 Redis 從節(jié)點讀取數(shù)據(jù)時,很容易讀取到已經(jīng)過期的數(shù)據(jù)。

在 Redis 3.2 中,從節(jié)點在讀取數(shù)據(jù)時,增加了對數(shù)據(jù)是否過期的判斷:如果該數(shù)據(jù)已過期,則不返回給客戶端;將 Redis 升級到 3.2 可以解決數(shù)據(jù)過期問題。

故障切換問題

在沒有使用哨兵的讀寫分離場景下,應(yīng)用針對讀和寫分別連接不同的 Redis 節(jié)點。

當(dāng)主節(jié)點或從節(jié)點出現(xiàn)問題而發(fā)生更改時,需要及時修改應(yīng)用程序讀寫 Redis 數(shù)據(jù)的連接;連接的切換可以手動進行,或者自己寫監(jiān)控程序進行切換,但前者響應(yīng)慢、容易出錯,后者實現(xiàn)復(fù)雜,成本都不算低。

總結(jié):在使用讀寫分離之前,可以考慮其他方法增加 Redis 的讀負載能力:如盡量優(yōu)化主節(jié)點(減少慢查詢、減少持久化等其他情況帶來的阻塞等)提高負載能力;使用 Redis 集群同時提高讀負載能力和寫負載能力等。

如果使用讀寫分離,可以使用哨兵,使主從節(jié)點的故障切換盡可能自動化,并減少對應(yīng)用程序的侵入。

復(fù)制超時問題

主從節(jié)點復(fù)制超時是導(dǎo)致復(fù)制中斷的最重要的原因之一,本小節(jié)單獨說明超時問題,下一小節(jié)說明其他會導(dǎo)致復(fù)制中斷的問題。

超時判斷意義

在復(fù)制連接建立過程中及之后,主從節(jié)點都有機制判斷連接是否超時,其意義在于:

  • 如果主節(jié)點判斷連接超時,其會釋放相應(yīng)從節(jié)點的連接,從而釋放各種資源,否則無效的從節(jié)點仍會占用主節(jié)點的各種資源(輸出緩沖區(qū)、帶寬、連接等)。

此外連接超時的判斷可以讓主節(jié)點更準(zhǔn)確的知道當(dāng)前有效從節(jié)點的個數(shù),有助于保證數(shù)據(jù)安全(配合前面講到的 min-slaves-to-write 等參數(shù))。

  • 如果從節(jié)點判斷連接超時,則可以及時重新建立連接,避免與主節(jié)點數(shù)據(jù)長期的不一致。

判斷機制

主從復(fù)制超時判斷的核心,在于 repl-timeout 參數(shù),該參數(shù)規(guī)定了超時時間的閾值(默認 60s),對于主節(jié)點和從節(jié)點同時有效。

  • 主從節(jié)點觸發(fā)超時的條件分別如下:
  • 主節(jié)點:每秒1次調(diào)用復(fù)制定時函數(shù) replicationCron(),在其中判斷當(dāng)前時間距離上次收到各個從節(jié)點 REPLCONF ACK 的時間,是否超過了 repl-timeout 值,如果超過了則釋放相應(yīng)從節(jié)點的連接。

從節(jié)點:從節(jié)點對超時的判斷同樣是在復(fù)制定時函數(shù)中判斷。

從節(jié)點的基本邏輯是:

  • 如果當(dāng)前處于連接建立階段,且距離上次收到主節(jié)點的信息的時間已超過 repl-timeout,則釋放與主節(jié)點的連接。
  • 如果當(dāng)前處于數(shù)據(jù)同步階段,且收到主節(jié)點的 RDB 文件的時間超時,則停止數(shù)據(jù)同步,釋放連接。
  • 如果當(dāng)前處于命令傳播階段,且距離上次收到主節(jié)點的 PING 命令或數(shù)據(jù)的時間已超過 repl-timeout 值,則釋放與主節(jié)點的連接。

主從節(jié)點判斷連接超時的相關(guān)源代碼如下:

  1. /* Replication cron function, called 1 time per second. */ 
  2. void replicationCron(void) { 
  3.    static long long replication_cron_loops = 0; 
  4.  
  5.    /* Non blocking connection timeout? */ 
  6.    if (server.masterhost && 
  7.        (server.repl_state == REDIS_REPL_CONNECTING || 
  8.         slaveIsInHandshakeState()) && 
  9.         (time(NULL)-server.repl_transfer_lastio) > server.repl_timeout) 
  10.    { 
  11.        redisLog(REDIS_WARNING,"Timeout connecting to the MASTER..."); 
  12.        undoConnectWithMaster(); 
  13.    } 
  14.  
  15.    /* Bulk transfer I/O timeout? */ 
  16.    if (server.masterhost && server.repl_state == REDIS_REPL_TRANSFER && 
  17.        (time(NULL)-server.repl_transfer_lastio) > server.repl_timeout) 
  18.    { 
  19.        redisLog(REDIS_WARNING,"Timeout receiving bulk data from MASTER... If the problem persists try to set the 'repl-timeout' parameter in redis.conf to a larger value."); 
  20.        replicationAbortSyncTransfer(); 
  21.    } 
  22.  
  23.    /* Timed out master when we are an already connected slave? */ 
  24.    if (server.masterhost && server.repl_state == REDIS_REPL_CONNECTED && 
  25.        (time(NULL)-server.master->lastinteraction) > server.repl_timeout) 
  26.    { 
  27.        redisLog(REDIS_WARNING,"MASTER timeout: no data nor PING received..."); 
  28.        freeClient(server.master); 
  29.    } 
  30.  
  31.    //此處省略無關(guān)代碼…… 
  32.  
  33.    /* Disconnect timedout slaves. */ 
  34.    if (listLength(server.slaves)) { 
  35.        listIter li; 
  36.        listNode *ln; 
  37.        listRewind(server.slaves,&li); 
  38.        while((ln = listNext(&li))) { 
  39.            redisClient *slave = ln->value; 
  40.            if (slave->replstate != REDIS_REPL_ONLINE) continue
  41.            if (slave->flags & REDIS_PRE_PSYNC) continue
  42.            if ((server.unixtime - slave->repl_ack_time) > server.repl_timeout) 
  43.            { 
  44.                redisLog(REDIS_WARNING, "Disconnecting timedout slave: %s"
  45.                    replicationGetSlaveName(slave)); 
  46.                freeClient(slave); 
  47.            } 
  48.        } 
  49.    } 
  50.  
  51.    //此處省略無關(guān)代碼…… 
  52.  

需要注意的坑

下面介紹與復(fù)制階段連接超時有關(guān)的一些實際問題:

數(shù)據(jù)同步階段:在主從節(jié)點進行全量復(fù)制 bgsave 時,主節(jié)點需要首先 fork 子進程將當(dāng)前數(shù)據(jù)保存到 RDB 文件中,然后再將 RDB 文件通過網(wǎng)絡(luò)傳輸?shù)綇墓?jié)點。

如果 RDB 文件過大,主節(jié)點在 fork 子進程+保存 RDB 文件時耗時過多,可能會導(dǎo)致從節(jié)點長時間收不到數(shù)據(jù)而觸發(fā)超時。

此時從節(jié)點會重連主節(jié)點,然后再次全量復(fù)制,再次超時,再次重連……這是個悲傷的循環(huán)。

為了避免這種情況的發(fā)生,除了注意 Redis 單機數(shù)據(jù)量不要過大,另一方面就是適當(dāng)增大 repl-timeout 值,具體的大小可以根據(jù) bgsave 耗時來調(diào)整。

命令傳播階段:如前所述,在該階段主節(jié)點會向從節(jié)點發(fā)送 PING 命令,頻率由 repl-ping-slave-period 控制;該參數(shù)應(yīng)明顯小于 repl-timeout 值(后者至少是前者的幾倍)。

否則,如果兩個參數(shù)相等或接近,網(wǎng)絡(luò)抖動導(dǎo)致個別 PING 命令丟失,此時恰巧主節(jié)點也沒有向從節(jié)點發(fā)送數(shù)據(jù),則從節(jié)點很容易判斷超時。

慢查詢導(dǎo)致的阻塞:如果主節(jié)點或從節(jié)點執(zhí)行了一些慢查詢(如 keys * 或者對大數(shù)據(jù)的 hgetall 等),導(dǎo)致服務(wù)器阻塞;阻塞期間無法響應(yīng)復(fù)制連接中對方節(jié)點的請求,可能導(dǎo)致復(fù)制超時。

復(fù)制中斷問題

主從節(jié)點超時是復(fù)制中斷的原因之一,除此之外,還有其他情況可能導(dǎo)致復(fù)制中斷,其中最主要的是復(fù)制緩沖區(qū)溢出問題。

復(fù)制緩沖區(qū)溢出

前面曾提到過,在全量復(fù)制階段,主節(jié)點會將執(zhí)行的寫命令放到復(fù)制緩沖區(qū)中。

該緩沖區(qū)存放的數(shù)據(jù)包括了以下幾個時間段內(nèi)主節(jié)點執(zhí)行的寫命令:

  • bgsave 生成 RDB 文件。
  • RDB 文件由主節(jié)點發(fā)往從節(jié)點。
  • 從節(jié)點清空老數(shù)據(jù)并載入 RDB 文件中的數(shù)據(jù)。

當(dāng)主節(jié)點數(shù)據(jù)量較大,或者主從節(jié)點之間網(wǎng)絡(luò)延遲較大時,可能導(dǎo)致該緩沖區(qū)的大小超過了限制,此時主節(jié)點會斷開與從節(jié)點之間的連接。

這種情況可能引起全量復(fù)制→復(fù)制緩沖區(qū)溢出導(dǎo)致連接中斷→重連→全量復(fù)制→復(fù)制緩沖區(qū)溢出導(dǎo)致連接中斷……的循環(huán)。

復(fù)制緩沖區(qū)的大小由 client-output-buffer-limit slave {hard limit} {soft limit} {soft seconds} 配置,默認值為 client-output-buffer-limit slave 256MB 64MB 60。

其含義是:如果 buffer 大于 256MB,或者連續(xù) 60s 大于 64MB,則主節(jié)點會斷開與該從節(jié)點的連接。該參數(shù)是可以通過 config set 命令動態(tài)配置的(即不重啟 Redis 也可以生效)。

當(dāng)復(fù)制緩沖區(qū)溢出時,主節(jié)點打印日志如下所示:

需要注意的是,復(fù)制緩沖區(qū)是客戶端輸出緩沖區(qū)的一種,主節(jié)點會為每一個從節(jié)點分別分配復(fù)制緩沖區(qū);而復(fù)制積壓緩沖區(qū)則是一個主節(jié)點只有一個,無論它有多少個從節(jié)點。

各場景下復(fù)制的選擇及優(yōu)化技巧

在介紹了 Redis 復(fù)制的種種細節(jié)之后,現(xiàn)在我們可以來總結(jié)一下,在下面常見的場景中,何時使用部分復(fù)制,以及需要注意哪些問題。

***次建立復(fù)制

此時全量復(fù)制不可避免,但仍有幾點需要注意:如果主節(jié)點的數(shù)據(jù)量較大,應(yīng)該盡量避開流量的高峰期,避免造成阻塞。

如果有多個從節(jié)點需要建立對主節(jié)點的復(fù)制,可以考慮將幾個從節(jié)點錯開,避免主節(jié)點帶寬占用過大。

此外,如果從節(jié)點過多,也可以調(diào)整主從復(fù)制的拓撲結(jié)構(gòu),由一主多從結(jié)構(gòu)變?yōu)闃錉罱Y(jié)構(gòu)(中間的節(jié)點既是其主節(jié)點的從節(jié)點,也是其從節(jié)點的主節(jié)點)。

但使用樹狀結(jié)構(gòu)應(yīng)該謹慎:雖然主節(jié)點的直接從節(jié)點減少,降低了主節(jié)點的負擔(dān),但是多層從節(jié)點的延遲增大,數(shù)據(jù)一致性變差;且結(jié)構(gòu)復(fù)雜,維護相當(dāng)困難。

主節(jié)點重啟

主節(jié)點重啟可以分為兩種情況來討論,一種是故障導(dǎo)致宕機,另一種則是有計劃的重啟。

主節(jié)點宕機:主節(jié)點宕機重啟后,runid 會發(fā)生變化,因此不能進行部分復(fù)制,只能全量復(fù)制。

實際上在主節(jié)點宕機的情況下,應(yīng)進行故障轉(zhuǎn)移處理,將其中的一個從節(jié)點升級為主節(jié)點,其他從節(jié)點從新的主節(jié)點進行復(fù)制;且故障轉(zhuǎn)移應(yīng)盡量的自動化,后面文章將要介紹的哨兵便可以進行自動的故障轉(zhuǎn)移。

安全重啟 debug reload:在一些場景下,可能希望對主節(jié)點進行重啟,例如主節(jié)點內(nèi)存碎片率過高,或者希望調(diào)整一些只能在啟動時調(diào)整的參數(shù)。

如果使用普通的手段重啟主節(jié)點,會使得 runid 發(fā)生變化,可能導(dǎo)致不必要的全量復(fù)制。

為了解決這個問題,Redis 提供了 debug reload 的重啟方式:重啟后,主節(jié)點的 runid 和 offset 都不受影響,避免了全量復(fù)制。

如下圖所示,debug reload 重啟后 runid 和 offset 都未受影響:

但 debug reload 是一柄雙刃劍:它會清空當(dāng)前內(nèi)存中的數(shù)據(jù),重新從 RDB 文件中加載,這個過程會導(dǎo)致主節(jié)點的阻塞,因此也需要謹慎。

從節(jié)點重啟

從節(jié)點宕機重啟后,其保存的主節(jié)點的 runid 會丟失,因此即使再次執(zhí)行 slaveof,也無法進行部分復(fù)制。

網(wǎng)絡(luò)中斷

如果主從節(jié)點之間出現(xiàn)網(wǎng)絡(luò)問題,造成短時間內(nèi)網(wǎng)絡(luò)中斷,可以分為多種情況討論。

***種情況:網(wǎng)絡(luò)問題時間極為短暫,只造成了短暫的丟包,主從節(jié)點都沒有判定超時(未觸發(fā) repl-timeout);此時只需要通過 REPLCONF ACK 來補充丟失的數(shù)據(jù)即可。

第二種情況:網(wǎng)絡(luò)問題時間很長,主從節(jié)點判斷超時(觸發(fā)了 repl-timeout),且丟失的數(shù)據(jù)過多,超過了復(fù)制積壓緩沖區(qū)所能存儲的范圍;此時主從節(jié)點無法進行部分復(fù)制,只能進行全量復(fù)制。

為了盡可能避免這種情況的發(fā)生,應(yīng)該根據(jù)實際情況適當(dāng)調(diào)整復(fù)制積壓緩沖區(qū)的大小;此外及時發(fā)現(xiàn)并修復(fù)網(wǎng)絡(luò)中斷,也可以減少全量復(fù)制。

第三種情況:介于前述兩種情況之間,主從節(jié)點判斷超時,且丟失的數(shù)據(jù)仍然都在復(fù)制積壓緩沖區(qū)中;此時主從節(jié)點可以進行部分復(fù)制。

復(fù)制相關(guān)的配置

這一節(jié)總結(jié)一下與復(fù)制有關(guān)的配置,說明這些配置的作用、起作用的階段,以及配置方法等。

通過了解這些配置,一方面加深對 Redis 復(fù)制的了解,另一方面掌握這些配置的方法,可以優(yōu)化 Redis 的使用,少走坑。

配置大致可以分為主節(jié)點相關(guān)配置、從節(jié)點相關(guān)配置以及與主從節(jié)點都有關(guān)的配置,下面分別說明。

與主從節(jié)點都有關(guān)的配置

首先介紹最特殊的配置,它決定了該節(jié)點是主節(jié)點還是從節(jié)點:

  • slaveof <masterip> <masterport>:Redis 啟動時起作用;作用是建立復(fù)制關(guān)系,開啟了該配置的 Redis 服務(wù)器在啟動后成為從節(jié)點。該注釋默認注釋掉,即 Redis 服務(wù)器默認都是主節(jié)點。
  • repl-timeout 60:與各個階段主從節(jié)點連接超時判斷有關(guān),見前面的介紹。

主節(jié)點相關(guān)配置

repl-diskless-sync no:作用于全量復(fù)制階段,控制主節(jié)點是否使用 diskless 復(fù)制(無盤復(fù)制)。

所謂 diskless 復(fù)制,是指在全量復(fù)制時,主節(jié)點不再先把數(shù)據(jù)寫入 RDB 文件,而是直接寫入 slave 的 socket 中,整個過程中不涉及硬盤。

diskless 復(fù)制在磁盤 IO 很慢而網(wǎng)速很快時更有優(yōu)勢。需要注意的是,截至 Redis 3.0,diskless 復(fù)制處于實驗階段,默認是關(guān)閉的。

repl-diskless-sync-delay 5:該配置作用于全量復(fù)制階段,當(dāng)主節(jié)點使用 diskless 復(fù)制時,該配置決定主節(jié)點向從節(jié)點發(fā)送之前停頓的時間,單位是秒;只有當(dāng) diskless 復(fù)制打開時有效,默認 5s。

之所以設(shè)置停頓時間,是基于以下兩個考慮:

  • 向 slave 的 socket 的傳輸一旦開始,新連接的 slave 只能等待當(dāng)前數(shù)據(jù)傳輸結(jié)束,才能開始新的數(shù)據(jù)傳輸。
  • 多個從節(jié)點有較大的概率在短時間內(nèi)建立主從復(fù)制。

client-output-buffer-limit slave 256MB 64MB 60:與全量復(fù)制階段主節(jié)點的緩沖區(qū)大小有關(guān),見前面的介紹。

repl-disable-tcp-nodelay no:與命令傳播階段的延遲有關(guān),見前面的介紹。

masterauth <master-password>:與連接建立階段的身份驗證有關(guān),見前面的介紹。

repl-ping-slave-period 10:與命令傳播階段主從節(jié)點的超時判斷有關(guān),見前面的介紹。

repl-backlog-size 1mb:復(fù)制積壓緩沖區(qū)的大小,見前面的介紹。

repl-backlog-ttl 3600:當(dāng)主節(jié)點沒有從節(jié)點時,復(fù)制積壓緩沖區(qū)保留的時間,這樣當(dāng)斷開的從節(jié)點重新連進來時,可以進行全量復(fù)制;默認 3600s。如果設(shè)置為 0,則永遠不會釋放復(fù)制積壓緩沖區(qū)。

min-slaves-to-write 3 與 min-slaves-max-lag 10:規(guī)定了主節(jié)點的最小從節(jié)點數(shù)目,及對應(yīng)的***延遲,見前面的介紹。

從節(jié)點相關(guān)配置

slave-serve-stale-data yes:與從節(jié)點數(shù)據(jù)陳舊時是否響應(yīng)客戶端命令有關(guān),見前面的介紹。

slave-read-only yes:從節(jié)點是否只讀;默認是只讀的。由于從節(jié)點開啟寫操作容易導(dǎo)致主從節(jié)點的數(shù)據(jù)不一致,因此該配置盡量不要修改。

單機內(nèi)存大小限制

在深入學(xué)習(xí) Redis 持久化一文中,講到了 fork 操作對 Redis 單機內(nèi)存大小的限制。實際上在 Redis 的使用中,限制單機內(nèi)存大小的因素非常之多。

下面總結(jié)一下在主從復(fù)制中,單機內(nèi)存過大可能造成的影響:

  • 切主:當(dāng)主節(jié)點宕機時,一種常見的容災(zāi)策略是將其中一個從節(jié)點提升為主節(jié)點,并將其他從節(jié)點掛載到新的主節(jié)點上,此時這些從節(jié)點只能進行全量復(fù)制。

如果 Redis 單機內(nèi)存達到 10GB,一個從節(jié)點的同步時間在幾分鐘的級別;如果從節(jié)點較多,恢復(fù)的速度會更慢。

如果系統(tǒng)的讀負載很高,而這段時間從節(jié)點無法提供服務(wù),會對系統(tǒng)造成很大的壓力。

  • 從庫擴容:如果訪問量突然增大,此時希望增加從節(jié)點分擔(dān)讀負載,如果數(shù)據(jù)量過大,從節(jié)點同步太慢,難以及時應(yīng)對訪問量的暴增。
  • 緩沖區(qū)溢出:(1)和(2)都是從節(jié)點可以正常同步的情形(雖然慢),但是如果數(shù)據(jù)量過大,導(dǎo)致全量復(fù)制階段主節(jié)點的復(fù)制緩沖區(qū)溢出,從而導(dǎo)致復(fù)制中斷。

則主從節(jié)點的數(shù)據(jù)同步會全量復(fù)制→復(fù)制緩沖區(qū)溢出導(dǎo)致復(fù)制中斷→重連→全量復(fù)制→復(fù)制緩沖區(qū)溢出導(dǎo)致復(fù)制中斷……的循環(huán)。

  • 超時:如果數(shù)據(jù)量過大,全量復(fù)制階段主節(jié)點 fork+ 保存 RDB 文件耗時過大,從節(jié)點長時間接收不到數(shù)據(jù)觸發(fā)超時。

主從節(jié)點的數(shù)據(jù)同步同樣可能陷入全量復(fù)制→超時導(dǎo)致復(fù)制中斷→重連→全量復(fù)制→超時導(dǎo)致復(fù)制中斷……的循環(huán)。

此外,主節(jié)點單機內(nèi)存除了絕對量不能太大,其占用主機內(nèi)存的比例也不應(yīng)過大:***只使用 50%-65% 的內(nèi)存,留下 30%-45% 的內(nèi)存用于執(zhí)行 bgsave 命令和創(chuàng)建復(fù)制緩沖區(qū)等。

info Replication

在 Redis 客戶端通過 info Replication 可以查看與復(fù)制相關(guān)的狀態(tài),對于了解主從節(jié)點的當(dāng)前狀態(tài),以及解決出現(xiàn)的問題都會有幫助。

主節(jié)點:

從節(jié)點:

對于從節(jié)點,上半部分展示的是其作為從節(jié)點的狀態(tài),從 connectd_slaves 開始,展示的是其作為潛在的主節(jié)點的狀態(tài)。

info Replication 中展示的大部分內(nèi)容在文章中都已經(jīng)講述,這里不再詳述。

總結(jié)

下面回顧一下本文的主要內(nèi)容:

  • 主從復(fù)制的作用:宏觀的了解主從復(fù)制是為了解決什么樣的問題,即數(shù)據(jù)冗余、故障恢復(fù)、讀負載均衡等。
  • 主從復(fù)制的操作:即 slaveof 命令。
  • 主從復(fù)制的原理:主從復(fù)制包括了連接建立階段、數(shù)據(jù)同步階段、命令傳播階段。

其中數(shù)據(jù)同步階段,有全量復(fù)制和部分復(fù)制兩種數(shù)據(jù)同步方式;命令傳播階段,主從節(jié)點之間有 PING 和 REPLCONF ACK 命令互相進行心跳檢測。

  • 應(yīng)用中的問題:包括讀寫分離的問題(數(shù)據(jù)不一致問題、數(shù)據(jù)過期問題、故障切換問題等)、復(fù)制超時問題、復(fù)制中斷問題等。

然后總結(jié)了主從復(fù)制相關(guān)的配置,其中 repl-timeout、client-output-buffer-limit slave 等對解決 Redis 主從復(fù)制中出現(xiàn)的問題可能會有幫助。

主從復(fù)制雖然解決或緩解了數(shù)據(jù)冗余、故障恢復(fù)、讀負載均衡等問題,但其缺陷仍很明顯:故障恢復(fù)無法自動化;寫操作無法負載均衡;存儲能力受到單機的限制。

這些問題的解決,需要哨兵和集群的幫助,我將在后面的文章中介紹,歡迎關(guān)注。

責(zé)任編輯:武曉燕 來源: 博客園
相關(guān)推薦

2018-09-11 09:33:49

Redis高可用架構(gòu)

2021-05-20 06:49:45

MongoDB高可用數(shù)據(jù)庫

2019-05-10 15:30:18

數(shù)據(jù)庫主從復(fù)制MySQL

2018-04-08 15:20:15

數(shù)據(jù)庫MySQL主從復(fù)制

2023-09-24 14:32:15

2018-06-12 09:33:45

Redis高可用AOF

2021-01-12 09:03:17

MySQL復(fù)制半同步

2020-06-08 08:20:11

Redis高可用集群

2021-01-11 14:45:35

Redis數(shù)據(jù)庫命令

2023-03-15 08:30:37

2023-03-19 11:53:27

2023-12-25 08:02:09

2023-03-19 22:38:12

邏輯復(fù)制PostgreSQL

2023-07-03 08:57:45

Master服務(wù)TCP

2019-12-05 10:00:03

架構(gòu)Redis服務(wù)器

2021-01-12 08:03:19

Redis數(shù)據(jù)系統(tǒng)

2024-07-04 08:00:24

2025-02-10 10:55:16

2024-03-01 18:33:59

MySQL節(jié)點數(shù)據(jù)

2021-06-08 07:48:27

MySQL主從配置
點贊
收藏

51CTO技術(shù)棧公眾號

亚洲网站视频福利| 欧美特级www| 97人人模人人爽人人少妇 | 亚洲综合男人的天堂| 国内精品国语自产拍在线观看| 日韩色图在线观看| 久久久精品久久久久久96| 精品国产91久久久久久久妲己| 国产h视频在线播放| 日本电影全部在线观看网站视频| 粉嫩aⅴ一区二区三区四区五区| 国内精品一区二区三区| 天天摸日日摸狠狠添| 高清日韩欧美| 欧美日韩黄视频| 国产青青在线视频| 草莓福利社区在线| 久久久精品蜜桃| 国产精品9999久久久久仙踪林 | 18在线观看的| 亚洲国产精品高清| 国产尤物99| 国产人妖一区二区三区| 日日摸夜夜添夜夜添精品视频| 蜜臀久久99精品久久久久久宅男 | 亚洲少妇30p| 欧洲国产精品| 日韩一级片免费观看| 国产一区二区在线电影| 国产精品免费一区豆花| 日日噜噜噜噜人人爽亚洲精品| 午夜欧美理论片| 日韩亚洲第一页| 在线不卡av电影| 日韩最新在线| 日韩风俗一区 二区| 少妇熟女视频一区二区三区| 日韩精品第二页| 欧美亚洲免费在线一区| 人妻熟女一二三区夜夜爱| 后进极品白嫩翘臀在线播放| 亚洲精品亚洲人成人网| 中文字幕在线亚洲三区| 国产女主播在线直播| 久久这里只有精品首页| 国产综合动作在线观看| 欧美亚洲精品在线观看| 成人一区二区三区中文字幕| 亚洲一区二区三区四区视频| 国产美女三级无套内谢| 久国产精品韩国三级视频| 国产伦精品免费视频| 欧美人一级淫片a免费播放| 久久裸体视频| 国产精品扒开腿做| 在线观看中文字幕码| 久久国产综合精品| 国产伊人精品在线| 91好色先生tv| 国产精品自在在线| 国产精品久久久久久久天堂第1集| 成人1区2区3区| 国产成人啪免费观看软件| 91久久伊人青青碰碰婷婷| 精品人妻aV中文字幕乱码色欲| 国产福利一区在线| 国产精品视频一区二区三区经| 黑人精品一区二区| 久久嫩草精品久久久精品一| 欧美一区1区三区3区公司| а天堂8中文最新版在线官网| 国产精品色眯眯| 亚洲成年人专区| 爱情岛论坛亚洲品质自拍视频网站| 亚洲国产综合色| 成人羞羞国产免费网站| 精品久久福利| 日韩精品一区二区三区中文不卡| 少妇被狂c下部羞羞漫画| 亚洲美女久久| xvideos亚洲人网站| 久久久无码一区二区三区| 中文日韩欧美| 国产日韩精品在线| 免费国产羞羞网站视频| 久久天堂av综合合色蜜桃网| 亚洲精品tv久久久久久久久| 欧美成人性生活视频| 亚洲一区二区三区四区在线免费观看| 欧美aⅴ在线观看| 日日夜夜综合| 日韩av影片在线观看| 干b视频在线观看| 中文无码久久精品| 亲子乱一区二区三区电影| 91久久精品无码一区二区| 成人免费高清在线观看| 日韩色妇久久av| 黑人玩欧美人三根一起进| 欧美在线free| 亚洲麻豆一区二区三区| 日韩在线精品| 欧美激情极品视频| 一区二区的视频| 26uuu亚洲综合色| 中文字幕av日韩精品| 一区二区三区短视频| 91精品国产品国语在线不卡| 成人精品在线观看视频| 欧美 日韩 国产一区二区在线视频 | 蜜臀久久精品| 在线播放91灌醉迷j高跟美女 | 亚洲综合免费观看高清完整版在线| 国产福利视频在线播放| 成人看片黄a免费看视频| 在线日韩欧美视频| 中文字幕第15页| 国产69精品久久99不卡| 一区二区精品免费视频| 成人欧美一区二区三区的电影| 日韩欧美国产三级| 欧美色图17p| 久久久999| 精品亚洲欧美日韩| 激情影院在线| 日韩一区二区免费在线观看| 亚洲一级黄色录像| 久久精品一区二区三区中文字幕 | 秋霞网一区二区| 最新热久久免费视频| 男女无套免费视频网站动漫| 啪啪国产精品| 国产69精品99久久久久久宅男| 国产精品无码一区二区桃花视频| 欧美激情一区二区在线| av无码精品一区二区三区| 窝窝社区一区二区| 性欧美长视频免费观看不卡| 精品乱子伦一区二区| 综合电影一区二区三区 | 日本一区二区三区中文字幕 | 国产jjizz一区二区三区视频| 亚洲欧洲一区二区天堂久久| 国产不卡一区二区在线观看| 直接在线观看的三级网址| 欧美精品777| 中文字幕在线有码| 国产在线日韩欧美| 男人的天堂视频在线| 亚州一区二区| 97热在线精品视频在线观看| 亚洲精品一区二区三区四区| 亚洲最大色网站| 一级黄色电影片| 夜夜嗨av一区二区三区网站四季av| 亚洲丝袜自拍清纯另类| 国精产品一区一区三区视频| 成人高潮a毛片免费观看网站| 九九九久久久久久| 亚洲免费黄色片| 同产精品九九九| 老牛影视av老牛影视av| 日韩精品久久久久久| 亚洲欧美日韩不卡一区二区三区| 黑人一区二区三区| 久久99视频精品| 欧美自拍第一页| 色一情一伦一子一伦一区| 大吊一区二区三区| 国产精品中文字幕欧美| av无码久久久久久不卡网站| 青青一区二区| 国产精品日韩欧美大师| caoporm免费视频在线| 亚洲成人a**站| www.国产毛片| 综合久久给合久久狠狠狠97色 | 少妇精品视频在线观看| 欧美肥婆姓交大片| 欧美高清电影在线| 欧美精品久久久久久久多人混战 | 精品国产精品自拍| 色综合99久久久无码国产精品| 老汉av免费一区二区三区| www国产免费| 综合国产视频| 91久久综合亚洲鲁鲁五月天| 98色花堂精品视频在线观看| 国产亚洲xxx| 草逼视频免费看| 欧美性猛交xxxx乱大交退制版| 日韩成人毛片视频| 久久先锋资源网| 日本黄色www| 奇米四色…亚洲| 草草视频在线免费观看| 成人亚洲一区二区| 久久青青草原| 日韩影片在线观看| 国产精品精品国产| 51漫画成人app入口| 中文字幕久热精品视频在线| 亚洲精品一区二区三区蜜桃| 在线观看日韩精品| 国产午夜视频在线播放| 亚洲同性gay激情无套| 国产三级视频网站| 国产宾馆实践打屁股91| 天天爽夜夜爽一区二区三区| 一区视频在线| 黄色免费高清视频| 精品理论电影在线| 久久99精品久久久久久青青日本| 99视频这里有精品| 国产精品99久久久久久久久久久久| 久草在线新免费首页资源站| 色偷偷噜噜噜亚洲男人的天堂| 神马亚洲视频| 欧美大胆人体bbbb| 国产普通话bbwbbwbbw| 欧洲精品视频在线观看| caoporn国产| 午夜精品福利一区二区三区av| 国产一二三区精品| 国产精品久久久久久亚洲毛片 | 亚洲婷婷在线视频| 精品人妻一区二区三区四区| av在线不卡电影| 催眠调教后宫乱淫校园| 国产成人亚洲综合a∨猫咪| 亚洲欧美视频二区| 免费成人在线观看| 国产wwwxx| 三级久久三级久久| 国产精品乱码久久久久| 免费在线亚洲| 99re在线视频免费观看| 午夜亚洲性色福利视频| www.中文字幕在线| 欧美专区在线| 欧美日韩亚洲一二三| 久久xxxx精品视频| 免费在线观看毛片网站| 天堂影院一区二区| 男人插女人下面免费视频| 日韩高清不卡在线| 91女神在线观看| 久久国产精品99精品国产| 天天色综合社区| 久久丁香综合五月国产三级网站| 亚洲激情在线观看视频| 久久精品免费看| 天天看片天天操| 韩国三级电影一区二区| www.成人黄色| 国产剧情在线观看一区二区 | 99久久免费国产| 亚洲精品在线视频免费观看| 91在线一区二区三区| 欧美特级黄色录像| 国产精品久久久久久户外露出| 国产精品麻豆免费版现看视频| 1000部国产精品成人观看| 在线免费观看亚洲视频| 亚洲成人777| 欧美a v在线播放| 一本综合精品| 国产成人av影视| 精品一区二区三区在线观看国产 | 人人精品久久| 91免费国产视频| 九九热播视频在线精品6| 噜噜噜噜噜久久久久久91| 成人精品视频| 国产精品自拍合集| 久久久精品午夜少妇| 亚洲人视频在线| 成人免费毛片片v| 亚洲AV无码成人精品区明星换面| 亚洲欧美一区二区视频| www.99re7.com| 91九色最新地址| av免费在线观看不卡| 亚洲第一福利在线观看| sese一区| 久久久天堂国产精品女人| 肉色欧美久久久久久久免费看| 国产精品一区二区久久久| 99久久人爽人人添人人澡| 婷婷四房综合激情五月| 黄色亚洲在线| gogogo高清免费观看在线视频| 国产成人亚洲综合色影视| 性猛交娇小69hd| 亚洲国产色一区| 亚洲天堂男人网| 亚洲国产又黄又爽女人高潮的| 午夜看片在线免费| 欧美亚洲另类视频| 精品亚洲二区| 视频一区二区在线观看| 亚洲国产午夜| 在线观看免费视频污| 久久久久久久久一| 久久久久亚洲av片无码下载蜜桃 | 992kp快乐看片永久免费网址| 国产成人综合亚洲网站| x88av在线| 狠狠色狠色综合曰曰| 东京干手机福利视频| 日韩小视频在线| 91成人抖音| 欧美成ee人免费视频| 亚洲一级电影| 日本黄色三级网站| 国产精品国产三级国产普通话蜜臀 | 国产免费视频在线| 97免费在线视频| 国产精品乱战久久久| 好色先生视频污| 美女视频一区二区| www.99热| 色又黄又爽网站www久久| 欧美 日韩 综合| 欧美精品国产精品日韩精品| 亚洲日日夜夜| 中文字幕成人一区| 久久国产剧场电影| 亚欧精品视频一区二区三区| 一本色道久久综合精品竹菊| 偷拍精品一区二区三区| 欧美激情一二三| 成人av激情人伦小说| 国产高清不卡无码视频| 国产一区二区中文字幕| 国产精品视频一区二区三| 欧美日韩精品一区二区三区| 福利在线播放| 国产精品美女久久| 久久国产精品成人免费观看的软件| 欧美激情精品久久久久久小说| 91麻豆免费视频| 国产一级免费视频| 亚洲欧美国产精品va在线观看| 午夜影视一区二区三区| 久久久精品动漫| 首页欧美精品中文字幕| 先锋影音av在线| 欧美久久一二三四区| 国产cdts系列另类在线观看| 成人免费在线视频网址| 亚洲天天综合| 亚洲精品乱码久久久久久9色| 亚洲影院在线观看| 色呦呦免费观看| 国产成人精彩在线视频九色| 国产传媒欧美日韩成人精品大片| 日韩av一二三四| 国产精品青草久久| 国产女人18毛片水18精| 欧美激情欧美激情| 台湾佬综合网| 网站一区二区三区| 亚洲欧美日韩在线不卡| 亚洲精品久久久蜜桃动漫| 亚洲**2019国产| 国产精品嫩草影院在线看| 一区二区免费av| 亚洲电影一区二区| 看电影就来5566av视频在线播放| 国产精品久久久久久久电影| 亚洲色图88| 88av在线播放| 欧美亚洲禁片免费| 免费在线看电影| 日本精品一区二区三区高清 久久| 人人狠狠综合久久亚洲| 特级片在线观看| 亚洲欧美日韩一区二区三区在线| 欧美大片1688网站| 久久综合久久久久| 国产午夜精品久久久久久免费视| 国产精品久久免费| 欧美亚洲国产视频小说| 外国成人免费视频| av网站有哪些| 在线电影欧美成精品| 蜜臀久久精品| 中文字幕在线乱| 久久精品亚洲麻豆av一区二区 | 91精品一区| 日韩在线一级片| 亚洲天堂精品在线观看| 视频在线不卡| 999在线免费观看视频| 三级久久三级久久久| 久久久精品视频免费| 色噜噜狠狠色综合网图区| 欧美深夜视频| 麻豆tv在线观看|