Redis主從同步

woniu4發表於2022-04-23

2.8版本以前

同步(snyc)

執行步驟:

  1. 從伺服器傳送snyc給主伺服器
  2. 主伺服器收到命令後,開始執行bgsave操作,將生成RDB檔案,將生成的RDB檔案同步給從服務。並使用一個緩衝區記錄從現在開始的寫命令
  3. 從服務載入接受到的RDB檔案,期間不可進行其他操作。
  4. 主服務將緩衝區裡的命令同步給從伺服器
    image-20220421140722352

傳播

同步完成之後,後續的命令都是通過傳播的方式傳送給從伺服器的。即當主服務執行完一條命令後,將該命令傳送給從服務,完成資料的同步。

缺陷

場景:

  • 首次複製,不存在問題,畢竟新連線上一個master伺服器,則需要複製其全量的資料
  • 斷開後重連複製,這是,仍是需要通過sync進行全量的複製,這就是很耗費資源的。畢竟如果斷開時間短,如中間網路抖動,導致中間短暫性斷開,再次複製全量資料,成本太高。

關於sync命令:

  1. 主伺服器需要執行bgsave命令來生成RDB檔案,這個操作會耗費主伺服器的大量CPU、記憶體和磁碟IO資源。
  2. 主伺服器將RDB檔案傳送給從伺服器,會消耗雙方的網路資源(頻寬和流量)。
  3. 接受到RDB檔案後,從伺服器需要載入RDB檔案,這個載入期間,從伺服器因為阻塞而沒有辦法處理命令請求。

2.8版本以後

psnyc具備完整重同步(full resynchronization)和部分重同步(partial resynchronization)。

其中,完整重同步sync的首次同步是一致的,通過主伺服器生成RDB檔案進行全量資料的同步,如果存在多個從伺服器,主伺服器僅會生成一份RDB檔案,分別同步給各個從伺服器。部分重同步則解決了sync斷開重連的問題,當斷開重連後,主伺服器在條件允許的前提下,僅會傳送斷開期間的寫命令。部分重同步的主要實現由以下三部分組成:

  • 主伺服器的複製偏移量(replication offset)和從伺服器的複製偏移量
  • 主伺服器的複製積壓緩衝區(replication backlogs)
  • 伺服器的執行ID(run ID)

複製偏移量

主伺服器記錄的是自己發給從伺服器的偏移量,從伺服器記錄的是自己接受到的資料偏移量。比如:當前主從伺服器的偏移量均為100,在有新的寫入命令後,主伺服器的偏移量變成了110,而從伺服器的是100,此時會有短暫的不一致,待主伺服器將新寫入命令同步給從伺服器後,從伺服器的偏移量會變更為110,此時主從伺服器又是保持一致的資料了。

複製積壓緩衝區

一個固定長度的先進先出佇列,預設1M,可通過配置repl_backlog_size調整其大小。當收到一條寫入命令,除了發給從伺服器外,還會將命令寫入到複製積壓緩衝區一份。

image-20220421164923114

當從伺服器A與主伺服器斷開後,中間的寫入命令會無法同步給從伺服器A,之後,重連後,從伺服器會將其複製偏移量告知主伺服器,如果該偏移量還在複製積壓緩衝區中,則直接將複製積壓緩衝區該偏移量後的命令傳送給從伺服器。

伺服器的執行ID

每個redis例項在啟動時候,都會隨機生成一個長度為40的唯一字串來標識當前執行的redis節點。當從伺服器對主伺服器進行首次複製時,則將自己的runID傳送給從伺服器,從伺服器會將這個ID儲存起來。當從伺服器與主伺服器斷開後重連時,會向主伺服器傳送當前儲存的runID,主伺服器收到後,會判斷與當前自己的runID是否一致,如果不一致,則進行全量複製;如果一致,則判斷複製偏移量是否還在複製積壓緩衝區中,如果還在,則進行部分重同步。

psync命令

psync <runId> <offset>

首次傳送時為psync ? -1,之後傳送的為上次master的runID和當前的複製偏移量。

缺陷

由於每次例項重啟都會重新生成runID,或者發生故障遷移後,新Master的runId必然與上一次的不一致,仍會導致完整重同步。

4.0版本以後的優化

解決了psnyc的缺陷,簡稱:psync2

第一種情況:redis重啟

第一步,在redis關閉時,通過shutdown save,都會呼叫rdbSaveInfoAuxFields函式,把當前例項的repl-id和repl-offset儲存到RDB檔案中。

第二步,重啟後載入RDB檔案中的複製資訊。把其中repl_id和repl_offset載入到例項中,分別賦給master_replid和master_repl_offset兩個變數值。

當從庫開啟了AOF持久化,redis載入順序發生變化優先載入AOF檔案,但是由於aof檔案中沒有複製資訊,所以導致重啟後從例項依舊使用全量複製!

第三步:向主庫上報復制資訊,判斷是否進行部分同步。

  • 從例項向主庫上報master_replid與主例項的master_replid1或replid2有一個相等,用於判斷主從未發生改變;
  • 從例項上報的master_repl_offset+1位元組,還存在於主例項的複製積壓緩衝區中,用於判斷從庫丟失部分是否在複製緩衝區中;
第二種情況: 故障切換

redis從庫預設開始複製積壓緩衝區,方便從庫切換為主庫,其他從庫可以直接從master節點獲取缺失的命令。通過兩組replId實現。

第一組:master_replid和master_repl_offset:如果redis是主例項,則表示為自己的replid和複製偏移量; 如果redis是從例項,則表示為自己主例項的replid1和同步主例項的複製偏移量。

第二組:master_replid2和second_repl_offset:無論主從,都表示自己上次主例項repid1和複製偏移量;用於兄弟例項或級聯複製,主庫故障切換psync。

判斷是否使用部分複製條件:如果從庫提供的master_replid與master的replid不同,且與master的replid2不同,或同步速度快於master; 就必須進行全量複製,否則執行部分複製。


公眾號:慢行的蝸牛

相關文章