Redis 主從複製 高可用和分佈式基石

點贊多大膽,就有多大產微信搜索公衆號【達摩克利斯之筆】獲取更多資源,文末有二維碼!

乾貨滿滿,擺好姿勢,三連發車

路漫漫其修遠兮,吾將上下而求索

主從複製介紹

概述

主從複製是將一臺Redis服務器的數據,複製到其他Redis服務器上,前者稱爲主節點(master/leader),後者稱爲從節點(slave/follower),一個主節點可以有多個從節點,但是一個從節點只能有一個主節點,數據的複製是單向的,只能從主節點複製到從節點。默認情況下,每一個Redis服務器都是一個主節點。

作用

  1. 數據備份:主從複製實現了數據的熱備份,提高數據的安全性
  2. 故障恢復:當主節點發生問題不能提供服務時,從節點可以提供服務,保證Redis集羣的可用性
  3. 負載均衡:在主從複製的基礎上,可以實現讀寫分離,主節點負責操作,從節點負責操作,在寫少讀多的場景下,可以使用該模式大大提高Redis的併發量
  4. Redis高可用:主從複製是實現哨兵和集羣的基礎,主從複製是Redis高可用的基石

主從複製實現

集羣準備

主從複製不會在同一臺節點上,我們準備三臺虛擬機,分別爲test201,test202,test203,Redis端口分別爲6379,6380和6381,我們將test201:6379當做主節點,餘下兩個爲從節點。我們使用之前講解的配置文件方式啓動三臺Redis節點。

實現方式

1、客戶端命令:Redis服務啓動後在客戶端使用slaveof <masterip> <masterport>,該Redis服務會成爲從節點。

127.0.0.1:6380> slaveof test201 6379

2、啓動命令:使用redis-server命令時使用 --slaveof <masterip> <masterport>,該Redis會成爲從節點

redis-server redis-6381.conf --slaveof test201 6379

3、配置文件:在從節點的配置文件中配置  slaveof <masterip> <masterport>

slaveof test201 6379

敲黑板:此三種方式實現Redis的主從複製,實現數據的熱備份,即主節點新增,刪除,修改key,從節點也會實時更新。

斷開主從關係

哪天想單飛或者另尋明主需要斷開現在主從關係,在從節點上運行slaveof no one,實現斷開,那麼從節點上的數據不會清空,但是不再接收主節點的數據更新

查看主從複製關係

在客戶端執行以下命令

info replication

test201:主節點,可以看出該節點是master,主節點,有一個從節點,ip爲192.168.109.203,端口爲6381

test203:從節點,可以看出該節點是slave,主節點是test201,端口爲6379

數據同步

數據同步概述

在Redis複製的基礎上從節點(slave)可以精確的複製主節點(master)上的數據,每當slave和master之間斷開連接時,slave會自動連接上master,並且無論這期間master發生了什麼,slave都會嘗試去同步精確的數據,稱爲master的精確副本。這個過程就是數據同步

Redis2.8之前,從節點向主節點發送sync命令請求數據同步,此時的同步時全量複製,Redis2.8之後從節點發送psync命令進行數據同步,此時根據主從節點當前狀態不同,同步的結果可能是全量複製或者部分複製。

  1. 全量複製:用於初次複製或其他無法部分複製的情況,將主節點中的所有數據都發送給從節點,是一個很重的操作。
  2. 部分複製:用於網絡中斷等情況的複製,只將中斷期間主節點的寫操作發送給從節點,相比全量複製不比較高效,如果連接斷開時間過長,導致主節點沒有完整的保存斷開時間內的數據,那麼還是會使用全量複製。

同步機制

  • 當一個 master 實例和一個 slave 實例連接正常時, master 會發送一連串的命令流來保持對 slave 的更新,以便於將自身數據集的改變複製給 slave , :包括客戶端的寫入、key 的過期或被逐出等等。

  • 當 master 和 slave 之間的連接斷開之後,因爲網絡問題、或者是主從意識到連接超時, slave 重新連接上 master 並會嘗試進行部分重同步:這意味着它會嘗試只獲取在斷開連接期間內丟失的命令流。

  • 當無法進行部分重同步時, slave 會請求進行全量重同步。這會涉及到一個更復雜的過程,例如 master 需要創建所有數據的快照,將之發送給 slave ,之後在數據集更改時持續發送命令流到 slave 。

Redis使用默認的異步複製,其特點是低延遲和高性能,是絕大多數 Redis 用例的自然複製模式。但是,slave會異步地確認其從master週期接收到的數據量。

全量複製

  1. slave判斷無法進行部分複製,向master發送全量複製請求,或slave發送部分複製,master判斷無法進行全量複製;
  2. master接收到全量複製指令之後,運行bgsave,在後臺生成RDB文件,並生成一個緩衝區(複製緩衝區),記錄從現在開始執行的所有寫命令
  3. master的bgsave執行完畢之後,將RDB文件發送給slave,slave首先清除自身舊數據,然後載入接收的RDB文件,將數據庫狀態更新至master執行bgsave時的數據庫狀態;
  4. master將上文提到的複製緩衝區中所有寫命令發送給slave,slave執行這些寫命令,將數據庫狀態更新至master最新狀態;
  5. 如果slave開啓了AOF,則會觸發bgrewriteaof操作,從而保證AOF文件更新到最新狀態。

從上述可以看出全量複製是一個很重的操作:

  1. master通過bgsave使進行fork子進程進行RDB持久化,該過程非常消耗CPU、內存、硬盤IO;
  2. master通過網絡將RDB文件發送給slave,對主/從節點的帶寬都有很大損耗;
  3. slvae清空老數據,載入新的RDB文件,這個過程是阻塞的,無法響應客戶端命令,slave執行bgrewrieaof也會到來損耗。

部分複製

因爲全量複製損耗太大,Redis2.8版本開始提供部分複製,用於處理網絡中斷時的數據同步。部分複製實現主要依賴於三個重要的概念:複製偏移量,複製積壓緩衝區,服務器運行ID

複製偏移量

主節點和從節點分別維護一個複製偏移量(offset),代表的是master向slave傳遞的字節數;主節點每次向從節點傳播N個字節數據時,主節點的offset增加N;從節點每次收到主節點傳來的N個字節數據時,從節點的offset增加N。offset用於判斷主從節點的數據庫狀態是否一致:如果二者offset相同,則一致;如果offset不同,則不一致,此時可以根據兩個offset找出從節點缺少的那部分數據。例如,如果主節點的offset是1000,而從節點的offset是500,那麼部分複製就需要將offset爲501-1000的數據傳遞給從節點。而offset爲501-1000的數據存儲的位置,就是下面要介紹的複製積壓緩衝區

複製積壓緩衝區

當主節點開始有從節點時創建,其作用是備份主節點最近發送給從節點的數據,複製積壓緩衝區由主節點創建、維護、固定長度、先進先出。無論主節點有幾個從節點,都只需要一個複製積壓緩衝區,默認大小爲1M。

在命令傳播階段,主節點除了將寫命令發送給從節點外還會發送一份給複製積壓緩衝區,作爲寫命令的備份,除了存儲寫命令,複製積壓緩衝區中還存儲了其中的每個字節對應的複製偏移量(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命令執行流程

1、首先從節點根據當前狀態,決定如何調用psync命令:

  • 如果從節點之前未執行過slaveof或最近執行了slaveof no one,則從節點發送命令爲psync ? -1,向主節點請求全量複製;
  • 如果從節點之前執行了slaveof,則發送命令爲psync <runid> <offset>,其中runid爲上次複製的主節點的runid,offset爲上次複製截止時從節點保存的複製偏移量。

2、主節點根據收到的psync命令,及當前服務器狀態,決定執行全量複製還是部分複製:

  • 如果主節點版本低於Redis2.8,則返回-ERR回覆,此時從節點重新發送sync命令執行全量複製;
  • 如果主節點版本夠新,且runid與從節點發送的runid相同,且從節點發送的offset之後的數據在複製積壓緩衝區中都存在,則回覆+CONTINUE,表示將進行部分複製,從節點等待主節點發送其缺少的數據即可;
  • 如果主節點版本夠新,但是runid與從節點發送的runid不同,或從節點發送的offset之後的數據已不在複製積壓緩衝區中(在隊列中被擠出了),則回覆+FULLRESYNC <runid> <offset>,表示要進行全量複製,其中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值。

總結

1、主從複製的作用:瞭解主從複製是爲了解決什麼樣的問題,即數據冗餘、故障恢復、讀負載均衡等。

2、主從複製的操作:即slaveof命令。

3、主從複製的原理:主從複製包括了連接建立階段、數據同步階段、命令傳播階段;其中數據同步階段,有全量複製和部分複製兩種數據同步方式;命令傳播階段,主從節點之間有PING和REPLCONF ACK命令互相進行心跳檢測。

主從複製雖然可以對數據進行熱備份,但其缺陷仍很明顯:故障恢復無法自動化;寫操作無法負載均衡;存儲能力受到單機的限制;這些問題的解決,需要哨兵和集羣的幫助,但是主從複製是實現Redis高可用的基石非常重要,Redis的哨兵模式,集羣模式已經發布大家可以查閱

《Redis Sentinel 哨兵模式》

《Redis Cluster 集羣模式》


有幫助喜歡的話點個贊留個言點個關注加個收藏來個一條龍,不喜歡沒幫助覺得坑爹請吐槽我,讓我知道錯在哪裏,總之不要不理我嘛,好不好

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章