詳解Redis主從複製原理

文章首發於公眾號 「蘑菇睡不著」

前言

Redis 的主從複製和 MySQL 差不多,主要起著 數據備份,讀寫分離等作用。所以說主從複製對 Redis 來說非常重要,而無論是面試還是工作總,了解 Redis主從複製 底層實現有非常有必要,那麼接下來就和大家來看看 Redis 主從複製是怎麼實現的吧。

什麼是 Redis 主從複製?

  在 Redis 中,我們可以通過 SLAVEOF 命令或者 slaveof 選項,讓一個伺服器去複製另一個伺服器,被複制的伺服器稱為「主伺服器」,發起複制的伺服器稱為「從伺服器」,由兩種伺服器組成的模式稱為「主從複製」。

  Redis 主從複製有以下特點:

  • Redis 使用非同步複製,slave 和 master 之間非同步地確認處理的數據量。
  • 一個 master 可以擁有多個 slave。
  • slave 可以接受其他 slave 的連接。除了多個 slave 可以連接到同一個 master 之外, slave 之間也可以像層疊狀的結構(cascading-like structure)連接到其他 slave 。自 Redis 4.0 起,所有的 sub-slave 將會從 master 收到完全一樣的複製流。
  • Redis 複製在 master 側是非阻塞的。這意味著 master 在一個或多個 slave 進行初次同步或者是部分重同步時,可以繼續處理查詢請求。
  • 複製在 slave 側大部分也是非阻塞的。當然這個是可配的,如果在 redis.conf配置是非阻塞的,可以使用舊數據集處理查詢請求;如果配置的是阻塞的,slave 會返回一個 error 給客戶端。

怎麼實現主從複製?

假設現在有兩個 Redis 伺服器,地址分別為 127.0.0.1:6379127.0.0.1:12345,如果在伺服器 127.0.0.1:12345 執行以下命令:

127.0.0.1:12345> SLAVEOF 127.0.0.1 6379
OK

那麼伺服器127.0.0.1:12345就是127.0.0.1:6379 的從伺服器。主從伺服器的數據會保持一致
比如主伺服器存儲數據:

127.0.0.1:6379> set msg "hello world"
OK

然後從伺服器就能直接獲取數據:

127.0.0.1:12345>get msg
"hello world"

刪除數據也是一樣,主從會保持一致。

主從複製原理

首先,Redis 的複製分為同步(sync)和命令傳播(command propagate)兩個操作:

  • 同步操作用於將從伺服器資料庫的狀態更新為主伺服器所處的狀態。
  • 命令傳播則相反,它主要作用在主伺服器的資料庫狀態更改時,導致主從伺服器的資料庫狀態出現不一致時,讓主從回到一致的的過程。

接下來詳細說說這兩種複製。

同步

文字解說:

  1. 客戶端向從伺服器發送 SLAVEOF 命令,先是判斷是否是第一次複製,第一次是複製一般是剛開始組建主從關係。
  2. 是第一次複製:從伺服器會向主伺服器發送 PSYNC ? -1 命令,請求主伺服器執行完整重同步操作。
  3. 主伺服器接到完整重同步請求之後,將在後台執行 BGSAVE 命令,在後台生成一個 RDB 文件,並使用一個複製積壓緩衝區記錄從現在開始執行的所有寫命令。
  4. BGSAVE 命令執行完畢之後,主伺服器會將 RDB 文件以及 緩衝區中記錄的寫命令發送給從伺服器,還會向從伺服器返回 +FULLRESYNC [主伺服器ID] [複製偏移量](和圖中的 偏移量 是一個)。
  5. 從伺服器接收到後,會載入 RDB 文件,並執行 主伺服器給的 寫命令,以此來達到和主伺服器一致的數據狀態。
  6. 如果不是第一次複製,那麼說明從伺服器可能是斷線,導致和主伺服器數據狀態不一致,需要同步主伺服器的數據。那麼從伺服器會按照下面的步驟來請求部分同步。
  7. 向主伺服器發送 PSYNC [主伺服器ID] [複製偏移量](這個是第一次複製時主伺服器傳過來的),主伺服器ID 時斷線前的主伺服器,用於定位去同步那個主伺服器的;複製偏移量是上一次同步的位置,用於定位具體的同步位置的。
  8. 主伺服器接收到從伺服器的命令後,並找到相應同步的位置後,會給從伺服器發送 +CONTINUE 命令,表示將於從伺服器執行部分同步操作,之後主伺服器會將保存在複製積壓緩衝區對應 複製偏移量之後的所有數據發送給從伺服器,但是如果找不到偏移量之後的數據,就會進行完整同步,這樣就可以讓從伺服器達到和主伺服器一致的狀態。

命令傳播

主從伺服器同步成功後,並不會一致保持這個狀態,主伺服器可能會執行寫命令,這也主從數據就不知一致了。
為了處理這種問題,主伺服器會把自己執行的寫命令發送給從伺服器,當從伺服器執行完這些命令之後,主從伺服器的數據就一致了

在命令傳播階段,從伺服器默認會以每秒一次的頻率,向主伺服器發送命令:
REPLCONF ACK <replication_offset>
<replication_offset> 是從伺服器當前的複製偏移量。
發送 REPLCONF ACK 命令對於主從伺服器有三個作用:

  • 檢測主從伺服器的網路狀態。
  • 輔助實現 min-slaves 選項。
  • 檢測命令丟失。

關鍵詞講解

  1. 主伺服器ID:用於標識一個伺服器。
  • 每個伺服器,無論是主伺服器還是從伺服器都有屬於自己獨一無二的 伺服器ID。
  • ID 在伺服器啟動時生成,由 40 個隨機的十六進位字元組成。
  1. 複製積壓緩衝區:複製積壓緩衝區是由主伺服器維護的一個固定長度、先進先出(FIFO)隊列,默認大小為 1MB。如下:
偏移量 10086 10087 10088 10089
位元組值 3 ‘\r’ ‘\n’ ‘$’

總結

Redis 主從複製主要是通過 PSYNC 命令實現。
複製分為 部分複製 以及 完整複製
部分複製通過 複製偏移量、複製積壓緩衝區、伺服器ID來實現。
完整複製通過 RDB 以及 複製積壓緩衝區來實現。
主從複製主要解決的是 數據備份、讀寫分離的問題。

最後

如果覺得文章對你有幫助,點贊、關注、轉發 統統走起來~

可以去公眾號 蘑菇睡不著 看看,更多精彩內容等你。

Tags: