Redis的主从复制是如何做的?复制过程中也会产生各种问题
點擊上方“朱小廝的博客”,選擇“設為星標”
后臺回復"書",獲取
來源:urlify.cn/bQbeAf
在Redis客戶端通過info replication可以查看與復制相關的狀態,對于了解主從節點的當前狀態,以及解決出現的問題都會有幫助。
主從復制,是指將一臺Redis服務器的數據,復制到其他的Redis服務器。前者稱為主節點(master/leader),后者稱為從節點(slave/follower);數據的復制是單向的,只能由主節點到從節點。
默認情況下,每臺Redis服務器都是主節點;且一個主節點可以有多個從節點(或沒有從節點),但一個從節點只能有一個主節點。
主從復制的作用主要包括:
數據冗余:主從復制實現了數據的熱備份,是持久化之外的一種數據冗余方式。
故障恢復:當主節點出現問題時,可以由從節點提供服務,實現快速的故障恢復;實際上是一種服務的冗余。
負載均衡:在主從復制的基礎上,配合讀寫分離,可以由主節點提供寫服務,由從節點提供讀服務(即寫Redis數據時應用連接主節點,讀Redis數據時應用連接從節點),分擔服務器負載;尤其是在寫少讀多的場景下,通過多個從節點分擔讀負載,可以大大提高Redis服務器的并發量。
高可用基石:除了上述作用以外,主從復制還是哨兵和集群能夠實施的基礎,因此說主從復制是Redis高可用的基礎。
如何使用主從復制
開啟主從復制
主從復制的開啟,完全是在從節點發起的;不需要我們在主節點做任何事情。
從節點開啟主從復制,有3種方式:
- 配置文件:在從服務器的配置文件中加入:slaveof 
- 啟動命令:redis-server啟動命令后加入 --slaveof 
- 客戶端命令:Redis服務器啟動后,直接通過客戶端執行命令:slaveof,則該Redis實例成為從節點。 
斷開主從復制
通過slaveof命令建立主從復制關系以后,可以通過slaveof no one斷開。
從節點斷開復制后,不會刪除已有的數據,只是不再接受主節點新的數據變化。
主從復制的實現原理
主從復制過程大體可以分為3個階段:連接建立階段(即準備階段)、數據同步階段、命令傳播階段;
連接建立階段
step1:保存主節點信息
從節點服務器內部維護了兩個字段,即masterhost和masterport字段,用于存儲主節點的ip和port信息。
slaveof是異步命令,從節點完成主節點ip和port的保存后,向發送slaveof命令的客戶端直接返回OK**,實際的復制操作在這之后才開始進行。**
step2:建立socket連接
從節點每秒1次調用復制定時函數replicationCron(),如果發現了有主節點可以連接,便會根據主節點的ip和port,創建socket連接。
如果連接成功:
從節點:為該socket建立一個專門處理復制工作的文件事件處理器,負責后續的復制工作,如接收RDB文件、接收命令傳播等。
主節點:接收到從節點的socket連接后(即accept之后),為該socket創建相應的客戶端狀態,并將從節點看做是連接到主節點的一個客戶端,后面的步驟會以從節點向主節點發送命令請求的形式來進行。
step3:發送ping命令
從節點成為主節點的客戶端之后,發送ping命令進行首次請求,目的是:檢查socket連接是否可用,以及主節點當前是否能夠處理請求。
從節點發送ping命令后,可能出現3種情況:
(1)返回pong:說明socket連接正常,且主節點當前可以處理請求,復制過程繼續。
(2)超時:一定時間后從節點仍未收到主節點的回復,說明socket連接不可用,則從節點斷開socket連接,并重連。
(3)返回pong以外的結果:如果主節點返回其他結果,如正在處理超時運行的腳本,說明主節點當前無法處理命令,則從節點斷開socket連接,并重連。
step4:身份驗證
如果從節點中設置了masterauth選項,則從節點需要向主節點進行身份驗證;沒有設置該選項,則不需要驗證。
從節點進行身份驗證是通過向主節點發送auth命令進行的,auth命令的參數即為配置文件中的masterauth的值。
如果主節點設置密碼的狀態,與從節點masterauth的狀態一致(一致是指都存在,且密碼相同,或者都不存在),則身份驗證通過,復制過程繼續;如果不一致,則從節點斷開socket連接,并重連。
step5:發送從節點端口信息
身份驗證之后,從節點會向主節點發送其監聽的端口號,主節點將該信息保存到該從節點對應的客戶端的slave_listening_port字段中;該端口信息除了在主節點中執行info Replication時顯示以外,沒有其他作用。
數據同步階段
主從節點之間的連接建立以后,便可以開始進行數據同步,該階段可以理解為從節點數據的初始化。
具體執行的方式是:從節點向主節點發送psync命令,開始同步。
數據同步階段是主從復制最核心的階段,根據主從節點當前狀態的不同,可以分為全量復制和部分復制。
在數據同步階段之前,從節點是主節點的客戶端,主節點不是從節點的客戶端;而到了這一階段及以后,主從節點互為客戶端。原因在于:在此之前,主節點只需要響應從節點的請求即可,不需要主動發請求,而在數據同步階段和后面的命令傳播階段,主節點需要主動向從節點發送請求(如推送緩沖區中的寫命令),才能完成復制。
命令傳播階段
數據同步階段完成后,主從節點進入命令傳播階段;在這個階段主節點將自己執行的寫命令發送給從節點,從節點接收命令并執行,從而保證主從節點數據的一致性。
在命令傳播階段,除了發送寫命令,主從節點還維持著心跳機制:PING和REPLCONF ACK。
PS:
延遲與不一致: 命令傳播是異步的過程,即主節點發送寫命令后并不會等待從節點的回復;因此實際上主從節點之間很難保持實時的一致性,延遲在所難免。數據不一致的程度,與主從節點之間的網絡狀況、主節點寫命令的執行頻率、以及主節點中的repl-disable-tcp-nodelay配置等有關。
repl-disable-tcp-nodelay no:該配置作用于命令傳播階段,控制主節點是否禁止與從節點的TCP_NODELAY;默認no,即不禁止TCP_NODELAY。當設置為yes時,TCP會對包進行合并從而減少帶寬,但是發送的頻率會降低,從節點數據延遲增加,一致性變差;具體發送頻率與Linux內核的配置有關,默認配置為40ms。當設置為no時,TCP會立馬將主節點的數據發送給從節點,帶寬增加但延遲變小。一般來說,只有當應用對Redis數據不一致的容忍度較高,且主從節點之間網絡狀況不好時,才會設置為yes;多數情況使用默認值no。
【數據同步階段】全量復制和部分復制
在Redis2.8以前,從節點向主節點發送sync命令請求同步數據,此時的同步方式是全量復制;
在Redis2.8以后,從節點可以發送psync命令請求同步數據,此時根據主從節點當前狀態的不同,同步方式可能是全量復制或部分復制。
全量復制:用于初次復制或其他無法進行部分復制的情況,將主節點中的所有數據都發送給從節點,是一個非常重型的操作。
部分復制:用于網絡中斷等情況后的復制,只將中斷期間主節點執行的寫命令發送給從節點,與全量復制相比更加高效。需要注意的是,如果網絡中斷時間過長,導致主節點沒有能夠完整地保存中斷期間執行的寫命令,則無法進行部分復制,仍使用全量復制。
全量復制
Redis通過psync命令進行全量復制的過程如下:
(1)從節點判斷無法進行部分復制,向主節點發送全量復制的請求;或從節點發送部分復制的請求,但主節點判斷無法進行全量復制;
(2)主節點收到全量復制的命令后,執行bgsave,在后臺生成RDB文件,并使用一個緩沖區(稱為復制緩沖區)記錄從現在開始執行的所有寫命令
(3)主節點的bgsave執行完成后,將RDB文件發送給從節點;從節點首先清除自己的舊數據,然后載入接收的RDB文件,將數據庫狀態更新至主節點執行bgsave時的數據庫狀態
(4)主節點將前述復制緩沖區中的所有寫命令發送給從節點,從節點執行這些寫命令,將數據庫狀態更新至主節點的最新狀態
(5)如果從節點開啟了AOF,則會觸發bgrewriteaof的執行,從而保證AOF文件更新至主節點的最新狀態
通過全量復制的過程可以看出,全量復制是非常重型的操作:
(1)主節點通過bgsave命令fork子進程進行RDB持久化,該過程是非常消耗CPU、內存(頁表復制)、硬盤IO的;
(2)主節點通過網絡將RDB文件發送給從節點,對主從節點的帶寬都會帶來很大的消耗
(3)從節點清空老數據、載入新RDB文件的過程是阻塞的,無法響應客戶端的命令;如果從節點執行bgrewriteaof,也會帶來額外的消耗
部分復制
由于全量復制在主節點數據量較大時效率太低,因此Redis2.8開始提供部分復制,用于處理網絡中斷時的數據同步。
部分復制的實現,依賴于三個重要的概念:復制偏移量,復制積壓緩沖區,服務器運行ID
復制偏移量
主節點和從節點分別維護一個復制偏移量(offset),代表的是主節點向從節點傳遞的字節數;主節點每次向從節點傳播N個字節數據時,主節點的offset增加N;從節點每次收到主節點傳來的N個字節數據時,從節點的offset增加N。
offset用于判斷主從節點的數據庫狀態是否一致:如果二者offset相同,則一致;如果offset不同,則不一致,此時可以根據兩個offset找出從節點缺少的那部分數據。例如,如果主節點的offset是1000,而從節點的offset是500,那么部分復制就需要將offset為501-1000的數據傳遞給從節點。而offset為501-1000的數據存儲的位置,就是下面要介紹的復制積壓緩沖區。
復制積壓緩沖區
復制積壓緩沖區是由主節點維護的、固定長度的、先進先出(FIFO)隊列,默認大小1MB;當主節點開始有從節點時創建,其作用是備份主節點最近發送給從節點的數據。注意,無論主節點有一個還是多個從節點,都只需要一個復制積壓緩沖區。
在命令傳播階段,主節點除了將寫命令發送給從節點,還會發送一份給復制積壓緩沖區,作為寫命令的備份;除了存儲寫命令,復制積壓緩沖區中還存儲了其中的每個字節對應的復制偏移量(offset)。由于復制積壓緩沖區定長且是先進先出,所以它保存的是主節點最近執行的寫命令;時間較早的寫命令會被擠出緩沖區。
由于該緩沖區長度固定且有限,因此可以備份的寫命令也有限,當主從節點offset的差距過大超過緩沖區長度時,將無法執行部分復制,只能執行全量復制。反過來說,為了提高網絡中斷時部分復制執行的概率,可以根據需要增大復制積壓緩沖區的大小(通過配置repl-backlog-size);例如如果網絡中斷的平均時間是60s,而主節點平均每秒產生的寫命令(特定協議格式)所占的字節數為100KB,則復制積壓緩沖區的平均需求為6MB,保險起見,可以設置為12MB,來保證絕大多數斷線情況都可以使用部分復制。
從節點將offset發送給主節點后,主節點根據offset和緩沖區大小決定能否執行部分復制:
- 如果offset偏移量之后的數據,仍然都在復制積壓緩沖區里,則執行部分復制; 
- 如果offset偏移量之后的數據已不在復制積壓緩沖區中(數據已被擠出),則執行全量復制。 
服務器運行ID(runid)
每個Redis節點(無論主從),在啟動時都會自動生成一個隨機ID(每次啟動都不一樣),由40個隨機的十六進制字符組成;
runid用來唯一識別一個Redis節點。通過info Server命令,可以查看節點的runid。
主從節點初次復制時,主節點將自己的runid發送給從節點,從節點將這個runid保存起來;當斷線重連時,從節點會將這個runid發送給主節點;主節點根據runid判斷能否進行部分復制:
- 如果從節點保存的runid與主節點現在的runid相同,說明主從節點之前同步過,主節點會繼續嘗試使用部分復制(到底能不能部分復制還要看offset和復制積壓緩沖區的情況); 
- 如果從節點保存的runid與主節點現在的runid不同,說明從節點在斷線前同步的Redis節點并不是當前的主節點,只能進行全量復制。 
psync命令的執行
image(1)首先從節點根據當前狀態,決定如何調用psync命令:
- 如果從節點之前未執行過slaveof或最近執行了slaveof no one,則從節點發送命令為psync ? -1,向主節點請求全量復制; 
- 如果從節點之前執行了slaveof,則發送命令為psync,其中runid為上次復制的主節點的runid,offset為上次復制截止時從節點保存的復制偏移量。 
(2)主節點根據收到的psync命令,及當前服務器狀態,決定執行全量復制還是部分復制:
- 如果主節點版本低于Redis2.8,則返回-ERR回復,此時從節點重新發送sync命令執行全量復制; 
- 如果主節點版本夠新,且runid與從節點發送的runid相同,且從節點發送的offset之后的數據在復制積壓緩沖區中都存在,則回復+CONTINUE,表示將進行部分復制,從節點等待主節點發送其缺少的數據即可; 
- 如果主節點版本夠新,但是runid與從節點發送的runid不同,或從節點發送的offset之后的數據已不在復制積壓緩沖區中(在隊列中被擠出了),則回復+FULLRESYNC,表示要進行全量復制,其中runid表示主節點當前的runid,offset表示主節點當前的offset,從節點保存這兩個值,以備使用。 
【命令傳播階段】心跳機制
在命令傳播階段,除了發送寫命令,主從節點還維持著心跳機制:PING和REPLCONF ACK。心跳機制對于主從復制的超時判斷、數據安全等有作用。
主->從:PING
每隔指定的時間,主節點會向從節點發送PING命令,這個PING命令的作用,主要是為了讓從節點進行超時判斷。
PING發送的頻率由 repl-ping-slave-period 參數控制,單位是秒,默認值是10s。
從->主:REPLCONF ACK
在命令傳播階段,**從節點會向主節點發送REPLCONF ACK命令,**頻率是每秒1次;命令格式為:REPLCONF ACK {offset},其中offset指從節點保存的復制偏移量。
REPLCONF ACK命令的作用包括:
(1)實時監測主從節點網絡狀態:該命令會被主節點用于復制超時的判斷。此外,在主節點中使用info Replication,可以看到其從節點的狀態中的lag值,代表的是主節點上次收到該REPLCONF ACK命令的時間間隔,在正常情況下,該值應該是0或1。
(2)檢測命令丟失:從節點發送了自身的offset,主節點會與自己的offset對比,如果從節點數據缺失(如網絡丟包),主節點會推送缺失的數據(這里也會利用復制積壓緩沖區)。注意,offset和復制積壓緩沖區,不僅可以用于部分復制,也可以用于處理命令丟失等情形;區別在于前者是在斷線重連后進行的,而后者是在主從節點沒有斷線的情況下進行的。
(3)輔助保證從節點的數量和延遲:Redis主節點中使用min-slaves-to-write和min-slaves-max-lag參數,來保證主節點在不安全的情況下不會執行寫命令;所謂不安全,是指從節點數量太少,或延遲過高。例如min-slaves-to-write和min-slaves-max-lag分別是3和10,含義是如果從節點數量小于3個,或所有從節點的延遲值都大于10s,則主節點拒絕執行寫命令。而這里從節點延遲值的獲取,就是通過主節點接收到REPLCONF ACK命令的時間來判斷的,即前面所說的info Replication中的lag值。
應用中的問題
讀寫分離及其中的問題
在主從復制基礎上實現的讀寫分離,可以實現Redis的讀負載均衡:由主節點提供寫服務,由一個或多個從節點提供讀服務(多個從節點既可以提高數據冗余程度,也可以最大化讀負載能力);
在使用Redis讀寫分離時需要注意的問題。
延遲與不一致問題
由于主從復制的命令傳播是異步的,延遲與數據的不一致不可避免。如果應用對數據不一致的接受程度程度較低,可能的優化措施包括:
優化主從節點之間的網絡環境(如在同機房部署);
監控主從節點延遲(通過offset)判斷,如果從節點延遲過大,通知應用不再通過該從節點讀取數據;
使用集群同時擴展寫負載和讀負載等。
在命令傳播階段以外的其他情況下,從節點的數據不一致可能更加嚴重,例如連接在數據同步階段,或從節點失去與主節點的連接時等。從節點的slave-serve-stale-data參數便與此有關:它控制這種情況下從節點的表現;如果為yes(默認值),則從節點仍能夠響應客戶端的命令,如果為no,則從節點只能響應info、slaveof等少數命令。該參數的設置與應用對數據一致性的要求有關;如果對數據一致性要求很高,則應設置為no。
數據過期問題
在單機版Redis中,存在兩種刪除策略:
- 惰性刪除:服務器不會主動刪除數據,只有當客戶端查詢某個數據時,服務器判斷該數據是否過期,如果過期則刪除。 
- 定期刪除:服務器執行定時任務刪除過期數據,但是考慮到內存和CPU的折中(刪除會釋放內存,但是頻繁的刪除操作對CPU不友好),該刪除的頻率和執行時間都受到了限制。 
在主從復制場景下,為了主從節點的數據一致性,從節點不會主動刪除數據,而是由主節點控制從節點中過期數據的刪除。由于主節點的惰性刪除和定期刪除策略,都不能保證主節點及時對過期數據執行刪除操作,因此,當客戶端通過Redis從節點讀取數據時,很容易讀取到已經過期的數據。Redis 3.2中,從節點在讀取數據時,增加了對數據是否過期的判斷:如果該數據已過期,則不返回給客戶端;將Redis升級到3.2可以解決數據過期問題。
故障切換問題
在沒有使用哨兵的讀寫分離場景下,應用針對讀和寫分別連接不同的Redis節點;當主節點或從節點出現問題而發生更改時,需要及時修改應用程序讀寫Redis數據的連接;連接的切換可以手動進行,或者自己寫監控程序進行切換,但前者響應慢、容易出錯,后者實現復雜,成本都不算低。
復制超時問題
主從節點復制超時是導致復制中斷的最重要的原因之一。
超時判斷意義: 在復制連接建立過程中及之后,主從節點都有機制判斷連接是否超時,其意義在于:
(1)如果主節點判斷連接超時,其會釋放相應從節點的連接,從而釋放各種資源,否則無效的從節點仍會占用主節點的各種資源(輸出緩沖區、帶寬、連接等);此外連接超時的判斷可以讓主節點更準確的知道當前有效從節點的個數,有助于保證數據安全(配合前面講到的min-slaves-to-write等參數)。
(2)如果從節點判斷連接超時,則可以及時重新建立連接,避免與主節點數據長期的不一致。
判斷機制
主從復制超時判斷的核心,在于repl-timeout參數,該參數規定了超時時間的閾值(默認60s),對于主節點和從節點同時有效;主從節點觸發超時的條件分別如下:
(1)主節點:每秒1次調用復制定時函數replicationCron(),在其中判斷當前時間距離上次收到各個從節點REPLCONF ACK的時間,是否超過了repl-timeout值,如果超過了則釋放相應從節點的連接。
(2)從節點:從節點對超時的判斷同樣是在復制定時函數中判斷,基本邏輯是:
- 如果當前處于連接建立階段,且距離上次收到主節點的信息的時間已超過repl-timeout,則釋放與主節點的連接; 
- 如果當前處于數據同步階段,且收到主節點的RDB文件的時間超時,則停止數據同步,釋放連接; 
- 如果當前處于命令傳播階段,且距離上次收到主節點的PING命令或數據的時間已超過repl-timeout值,則釋放與主節點的連接。 
復制階段連接超時有關的一些實際問題:
(1)數據同步階段:在主從節點進行全量復制bgsave時,主節點需要首先fork子進程將當前數據保存到RDB文件中,然后再將RDB文件通過網絡傳輸到從節點。如果RDB文件過大,主節點在fork子進程+保存RDB文件時耗時過多,可能會導致從節點長時間收不到數據而觸發超時;此時從節點會重連主節點,然后再次全量復制,再次超時,再次重連……這是個悲傷的循環。為了避免這種情況的發生,除了注意Redis單機數據量不要過大,另一方面就是適當增大repl-timeout值,具體的大小可以根據bgsave耗時來調整。
(2)命令傳播階段:在該階段主節點會向從節點發送PING命令,頻率由repl-ping-slave-period控制;該參數應明顯小于repl-timeout值(后者至少是前者的幾倍)。否則,如果兩個參數相等或接近,網絡抖動導致個別PING命令丟失,此時恰巧主節點也沒有向從節點發送數據,則從節點很容易判斷超時。
(3)慢查詢導致的阻塞:如果主節點或從節點執行了一些慢查詢(如keys *或者對大數據的hgetall等),導致服務器阻塞;阻塞期間無法響應復制連接中對方節點的請求,可能導致復制超時。
復制緩沖區溢出
在全量復制階段,主節點會將執行的寫命令放到復制緩沖區中,該緩沖區存放的數據包括了以下幾個時間段內主節點執行的寫命令:bgsave生成RDB文件、RDB文件由主節點發往從節點、從節點清空老數據并載入RDB文件中的數據。
當主節點數據量較大,或者主從節點之間網絡延遲較大時,可能導致該緩沖區的大小超過了限制,此時主節點會斷開與從節點之間的連接;這種情況可能引起全量復制->復制緩沖區溢出導致連接中斷->重連->全量復制->復制緩沖區溢出導致連接中斷……的循環。
復制緩沖區的大小由client-output-buffer-limit slave {hard limit} {soft limit} {soft seconds}配置,默認值為client-output-buffer-limit slave 256MB 64MB 60,其含義是:如果buffer大于256MB,或者連續60s大于64MB,則主節點會斷開與該從節點的連接。該參數是可以通過config set命令動態配置的(即不重啟Redis也可以生效)。
需要注意的是,復制緩沖區是客戶端輸出緩沖區的一種,主節點會為每一個從節點分別分配復制緩沖區;而復制積壓緩沖區則是一個主節點只有一個,無論它有多少個從節點。
各場景下復制的選擇及優化技巧
第一次建立復制
此時全量復制不可避免,但仍有幾點需要注意:
如果主節點的數據量較大,應該盡量避開流量的高峰期,避免造成阻塞;
如果有多個從節點需要建立對主節點的復制,可以考慮將幾個從節點錯開,避免主節點帶寬占用過大。
如果從節點過多,也可以調整主從復制的拓撲結構,由一主多從結構變為樹狀結構(中間的節點既是其主節點的從節點,也是其從節點的主節點);
但使用樹狀結構應該謹慎:雖然主節點的直接從節點減少,降低了主節點的負擔,但是多層從節點的延遲增大,數據一致性變差;且結構復雜,維護相當困難。
主節點重啟
主節點重啟可以分為兩種情況來討論,一種是故障導致宕機,另一種則是有計劃的重啟。
主節點宕機
主節點宕機重啟后,runid會發生變化,因此不能進行部分復制,只能全量復制。
實際上在主節點宕機的情況下,應進行故障轉移處理,將其中的一個從節點升級為主節點,其他從節點從新的主節點進行復制;且故障轉移應盡量的自動化。
安全重啟:debug reload
在一些場景下,可能希望對主節點進行重啟,例如主節點內存碎片率過高,或者希望調整一些只能在啟動時調整的參數。如果使用普通的手段重啟主節點,會使得runid發生變化,可能導致不必要的全量復制。
為了解決這個問題,Redis提供了debug reload的重啟方式:**重啟后,主節點的runid和offset****都不受影響,**避免了全量復制。
但debug reload是一柄雙刃劍:它會清空當前內存中的數據,重新從RDB文件中加載,這個過程會導致主節點的阻塞,因此也需要謹慎。
從節點重啟
從節點宕機重啟后,其保存的主節點的runid會丟失,因此即使再次執行slaveof,也無法進行部分復制。
網絡中斷
如果主從節點之間出現網絡問題,造成短時間內網絡中斷,可以分為多種情況討論。
第一種情況:網絡問題時間極為短暫,只造成了短暫的丟包,主從節點都沒有判定超時(未觸發repl-timeout);此時只需要通過REPLCONF ACK來補充丟失的數據即可。
第二種情況:網絡問題時間很長,主從節點判斷超時(觸發了repl-timeout),且丟失的數據過多,超過了復制積壓緩沖區所能存儲的范圍;此時主從節點無法進行部分復制,只能進行全量復制。為了盡可能避免這種情況的發生,應該根據實際情況適當調整復制積壓緩沖區的大小;此外及時發現并修復網絡中斷,也可以減少全量復制。
第三種情況:介于前述兩種情況之間,主從節點判斷超時,且丟失的數據仍然都在復制積壓緩沖區中;此時主從節點可以進行部分復制。
復制相關的配置
slaveof:Redis啟動時起作用;作用是建立復制關系,開啟了該配置的Redis服務器在啟動后成為從節點。該注釋默認注釋掉,即Redis服務器默認都是主節點。
repl-timeout 60:與各個階段主從節點連接超時判斷有關。
repl-diskless-sync no:作用于全量復制階段,控制主節點是否使用diskless復制(無盤復制)。所謂diskless復制,是指在全量復制時,主節點不再先把數據寫入RDB文件,而是直接寫入slave的socket中,整個過程中不涉及硬盤;diskless復制在磁盤IO很慢而網速很快時更有優勢。需要注意的是,截至Redis3.0,diskless復制處于實驗階段,默認是關閉的。
repl-diskless-sync-delay 5:該配置作用于全量復制階段,當主節點使用diskless復制時,該配置決定主節點向從節點發送之前停頓的時間,單位是秒;只有當diskless復制打開時有效,默認5s。之所以設置停頓時間,是基于以下兩個考慮:(1)向slave的socket的傳輸一旦開始,新連接的slave只能等待當前數據傳輸結束,才能開始新的數據傳輸 (2)多個從節點有較大的概率在短時間內建立主從復制。
client-output-buffer-limit slave 256MB 64MB 60:與全量復制階段主節點的緩沖區大小有關,見前面的介紹。
repl-disable-tcp-nodelay no:與命令傳播階段的延遲有關。
masterauth:與連接建立階段的身份驗證有關。
repl-ping-slave-period 10:與命令傳播階段主從節點的超時判斷有關。
repl-backlog-size 1mb:復制積壓緩沖區的大小。
repl-backlog-ttl 3600:當主節點沒有從節點時,復制積壓緩沖區保留的時間,這樣當斷開的從節點重新連進來時,可以進行全量復制;默認3600s。如果設置為0,則永遠不會釋放復制積壓緩沖區。
min-slaves-to-write 3與min-slaves-max-lag 10:規定了主節點的最小從節點數目,及對應的最大延遲,見前面的介紹。
slave-serve-stale-data yes:與從節點數據陳舊時是否響應客戶端命令有關,見前面的介紹。
slave-read-only yes:從節點是否只讀;默認是只讀的。由于從節點開啟寫操作容易導致主從節點的數據不一致,因此該配置盡量不要修改。
單機內存大小限制
fork操作對Redis單機內存大小的限制。實際上在Redis的使用中,限制單機內存大小的因素非常之多,單機內存過大可能造成的影響:
(1)切主:當主節點宕機時,一種常見的容災策略是將其中一個從節點提升為主節點,并將其他從節點掛載到新的主節點上,此時這些從節點只能進行全量復制;如果Redis單機內存達到10GB,一個從節點的同步時間在幾分鐘的級別;如果從節點較多,恢復的速度會更慢。如果系統的讀負載很高,而這段時間從節點無法提供服務,會對系統造成很大的壓力。
(2)從庫擴容:如果訪問量突然增大,此時希望增加從節點分擔讀負載,如果數據量過大,從節點同步太慢,難以及時應對訪問量的暴增。
(3)緩沖區溢出:(1)和(2)都是從節點可以正常同步的情形(雖然慢),但是如果數據量過大,導致全量復制階段主節點的復制緩沖區溢出,從而導致復制中斷,則主從節點的數據同步會全量復制->復制緩沖區溢出導致復制中斷->重連->全量復制->復制緩沖區溢出導致復制中斷……的循環。
(4)超時:如果數據量過大,全量復制階段主節點fork+保存RDB文件耗時過大,從節點長時間接收不到數據觸發超時,主從節點的數據同步同樣可能陷入全量復制->超時導致復制中斷->重連->全量復制->超時導致復制中斷……的循環。
此外,主節點單機內存除了絕對量不能太大,其占用主機內存的比例也不應過大:最好只使用50%-65%的內存,留下30%-45%的內存用于執行bgsave命令和創建復制緩沖區等。
想知道更多?掃描下面的二維碼關注我
后臺回復"技術",加入技術群
【精彩推薦】
- 超清晰的DNS入門指南
- 如何用ELK搭建TB級的日志系統
- 深度好文:Linux系統內存知識
- 日志采集系統都用到哪些技術?
- 面試官:為什么HashMap的加載因子是0.75?
- 原創|OpenAPI標準規范
- 如此簡單| ES最全詳細使用教程
- ClickHouse到底是什么?為什么如此牛逼!
- 原來ElasticSearch還可以這么理解
- 面試官:InnoDB中一棵B+樹可以存放多少行數據?
點個贊+在看,少個 bug?????
總結
以上是生活随笔為你收集整理的Redis的主从复制是如何做的?复制过程中也会产生各种问题的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 如何正确、高效地阅读源代码?
- 下一篇: 技术转管理的“苦”,我懂......
