一、什麼是主從同步?
主從同步,就是将資料備援備份,主庫(Master)将自己庫中的資料,同步給從庫(Slave)。
從庫可以一個,也可以多個,如圖所示:
二、為什麼需要主從同步?
Redis 雖然有 RDB 和 AOF 持久化技術,可以在伺服器重新開機的情況下保證記憶體中的資料不會丢失(但不意味着資料不丢,重新開機的時候還是會有不可用的情況)。
但是如果伺服器關閉後,再也起不來了(比如硬體故障),那意味着資料是完全丢失的!會對業務産生重大影響。
是以,主從同步的必要性,在于資料的高可用。它可以保證機器故障時,還有其他的伺服器可以進行故障轉移。
問題來了,多台伺服器備援同一份資料,Redis 是如何保證資料的一緻性的?
三、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 開始,從庫已支援增量同步,隻會把斷開的時候沒有發生的寫指令,同步給從庫。
詳細過程如下:
- 網絡恢複後,從庫發生 psync 指令給主庫,并攜帶之前主庫傳回的 runid,還有複制的偏移量 offset;
- 主庫收到指令後,核查 runid 和 offset,确認沒問題将響應 CONTINUE 指令;
- 主庫發送網絡斷開期間的寫指令,從庫接收指令并執行。
實際上,主庫在進行指令傳播的過程中,做了兩個事情:
- 發送寫指令給從庫;
- 寫指令寫入 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