天天看點

Redis 主從同步原理

作者:程式猿凱撒

一、什麼是主從同步?

主從同步,就是将資料備援備份,主庫(Master)将自己庫中的資料,同步給從庫(Slave)。

從庫可以一個,也可以多個,如圖所示:

Redis 主從同步原理

二、為什麼需要主從同步?

Redis 雖然有 RDB 和 AOF 持久化技術,可以在伺服器重新開機的情況下保證記憶體中的資料不會丢失(但不意味着資料不丢,重新開機的時候還是會有不可用的情況)。

但是如果伺服器關閉後,再也起不來了(比如硬體故障),那意味着資料是完全丢失的!會對業務産生重大影響。

是以,主從同步的必要性,在于資料的高可用。它可以保證機器故障時,還有其他的伺服器可以進行故障轉移。

問題來了,多台伺服器備援同一份資料,Redis 是如何保證資料的一緻性的?

三、Redis 是如何做到主從同步的?

簡單概括,有兩點:

  1. 一切修改隻在主庫進行:即主庫可讀可寫,從庫隻讀不可寫;
  2. 寫操作從主庫同步到從庫:全量同步、增量同步。

(一)全量同步

Redis 主從同步原理

1. 建立連接配接 協商同步

1.1 使用用戶端 redis-cli 連接配接從庫,執行 replicaof 指令,指定主庫 IP 和端口;

1.2 從庫響應後,執行 psync 指令,它包含 主庫 runid 和 複制偏移量 offset 兩個參數:

  • runid:啟動時自動生成随機唯一 ID。首次同步時,主庫 runid 未知,是以為 ?;
  • offset:表示複制的進度,第一次同步時,其值為 -1。

1.3 主庫收到 psync 指令後,使用 FULLRESYNC 指令響應從庫,同時也包含 主庫 runid 和 複制偏移量 offset 兩個參數,從庫會記錄這兩個參數。

注:replicaof 指令等同于 slaveof 指令,Redis 5.0 之前使用 slaveof 指令。

2. RDB 同步

2.1 主庫執行 bgsave 指令,此時将 fork 出子程序生成 RDB 檔案,新指令會寫入到緩沖區;

2.2 發送 RDB 檔案到從庫;

2.3 從庫清空資料後,載入 RDB 檔案。

注一:為保證資料一緻性,bgsave 執行後,主庫會持續寫入新指令到緩沖區,直到從庫加載 RDB 完成;

注二:bgsave 建立了子程序,子程序獨立負責 RDB 生成的工作,生成 RDB 的過程中,不會阻塞 Redis 主庫,主庫依然可以正常處理指令。

3. 指令同步

3.1 完成 RDB 載入後,從庫會回複确認消息給主庫,主庫會将緩沖區的寫指令發送給從庫;

3.2 從庫接收主庫的寫指令并執行,使得主從資料一緻。

注:指令執行後,長連接配接會一直保持,寫操作指令也會一直同步,保證主從資料的一緻性;

這個過程也稱為「基于長連接配接的指令傳播」。

(二)增量同步

指令傳播的過程中,如果出現 網絡故障 導緻連接配接斷開,此時新的寫指令将無法同步到從庫。

即便是抖動後斷開又恢複網絡連接配接,但此時 TCP 連接配接已經斷開,資料肯定是需要重新同步了。

  • 在 Redis 2.8 之前,從庫隻能和主庫重新發起全量同步,對于較大的 RDB 檔案,網絡恢複時間較長;
  • 從 Redis 2.8 開始,從庫已支援增量同步,隻會把斷開的時候沒有發生的寫指令,同步給從庫。
Redis 主從同步原理

詳細過程如下:

  1. 網絡恢複後,從庫發生 psync 指令給主庫,并攜帶之前主庫傳回的 runid,還有複制的偏移量 offset;
  2. 主庫收到指令後,核查 runid 和 offset,确認沒問題将響應 CONTINUE 指令;
  3. 主庫發送網絡斷開期間的寫指令,從庫接收指令并執行。

實際上,主庫在進行指令傳播的過程中,做了兩個事情:

  1. 發送寫指令給從庫;
  2. 寫指令寫入 repl_backlog_buffer 複制積壓緩沖區,儲存最近傳播的寫指令。

複制積壓緩沖區,是一個環形緩沖區。主庫除了擁有 repl_backlog_buffer,還存在複制點位 master_repl_offset;

同理,從庫,也有複制點位 slave_repl_offset;

如果從庫的 psync 指令指定的 offset,資料還存在 repl_backlog_buffer 緩沖區裡,也就是:

master_repl_offset - size < slave_repl_offset,即主庫最小的偏移量,小于從庫的偏移量,說明資料還在環形緩沖區裡。

是以,隻要主庫的緩沖區足夠大,足以容納最近的寫指令(Redis 協定),就可以在網絡中斷後使用增量同步了。

預設 repl_backlog_buffer = 1M,如果寫入資料量較大,比如 1M/s,顯然,網絡故障 1秒後,複制積壓緩沖區資料無效,是以應該增大它的值。

具體大小,需要根據實際情況确定。建議設定 10M 以上,大概就是 10s 以内的中斷,因為 Redis 伺服器啟動也需要一定時間。

作者:仁揚

連結:https://juejin.cn/post/7260455245935018043

繼續閱讀