2.8版本以前
同步(snyc)
執行步驟:
- 從伺服器傳送
snyc
給主伺服器 - 主伺服器收到命令後,開始執行
bgsave
操作,將生成RDB檔案,將生成的RDB檔案同步給從服務。並使用一個緩衝區記錄從現在開始的寫命令 - 從服務載入接受到的RDB檔案,期間不可進行其他操作。
- 主服務將緩衝區裡的命令同步給從伺服器
傳播
同步完成之後,後續的命令都是通過傳播的方式傳送給從伺服器的。即當主服務執行完一條命令後,將該命令傳送給從服務,完成資料的同步。
缺陷
場景:
- 首次複製,不存在問題,畢竟新連線上一個master伺服器,則需要複製其全量的資料
- 斷開後重連複製,這是,仍是需要通過
sync
進行全量的複製,這就是很耗費資源的。畢竟如果斷開時間短,如中間網路抖動,導致中間短暫性斷開,再次複製全量資料,成本太高。
關於sync
命令:
- 主伺服器需要執行
bgsave
命令來生成RDB檔案,這個操作會耗費主伺服器的大量CPU、記憶體和磁碟IO資源。 - 主伺服器將RDB檔案傳送給從伺服器,會消耗雙方的網路資源(頻寬和流量)。
- 接受到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調整其大小。當收到一條寫入命令,除了發給從伺服器外,還會將命令寫入到複製積壓緩衝區一份。
當從伺服器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; 就必須進行全量複製,否則執行部分複製。
公眾號:慢行的蝸牛