關於Redis的主從複製

:::tipredis

SLAVEOF host:port 命令能夠將當前服務器去複製目標服務器,進行復制中的主從服務器的數據庫將保存相同的數據,概念上稱爲數據庫狀態一致數據庫

:::服務器

舊版複製功能

同步(sync)

當從服務器發送SLAVEOF命令要求複製主服務器時,從服務器首先執行同步操做,即將從服務器的數據庫狀態更新至主服務器當前所處的數據庫狀態,具體步驟以下網絡

  1. 從服務器發送SYNC命令
  2. 收到命令的主服務執行BGSAVE命令,在後臺生成RDB文件,並使用緩衝區記錄從如今執行BGSAVE以後執行的全部寫命令
  3. 主服務器執行完BGSAVE以後,主服務器會將RDB文件發送給從服務器,從服務器接收並載入這個RDB文件
  4. 主服務器將記錄在緩衝區的全部寫命令發送給從服務器,從服務器執行這些寫命令

命令傳播(command propagate)

同步操做完成後,主從服務器目前的數據庫狀態達到一致,但這種狀態不是一成不變的,每當主服務器執行客戶端發送的寫命令時,主從服務器的數據庫就再也不一致設計

因此爲了保持主從服務器的數據一致,主服務器須要對從服務器執行命令傳播:將寫命令發送給從服務器,當從服務也執行完後,主從服務器將再次回到一致狀態3d

缺陷

舊版複製功能的缺陷主要體如今從服務器斷線重連的處理code

如上圖的狀況,從服務器在某一刻斷線,再此期間主服務器增長了k3,k4兩個鍵,按目前的實現邏輯,從服務器在以後重連後,依舊是再次發送SYNC命令進行同步(主服務器生成和發送RDB文件給從服務器載入)cdn

但其實從服務器主須要斷線期間的k3,k4鍵便可,RDB文件中的其餘鍵信息對從服務器來講都是沒必要要的blog

:::tip隊列

SYNC是一個很是耗資源的操做

  1. 主服務器須要執行BGSAVE來生成RDB文件,這耗費CPU,內存和磁盤IO資源
  2. 主服務器須要將RDB發送給從服務器,這耗費網絡帶寬
  3. 從服務器加載RDB文件時會阻塞其餘命令的處理

:::

新版複製功能

PSYNC命令替代SYNC

爲了解決斷線重連後的重同步問題,Redis2.8之後使用了PSYNC代替SYNC進行同步操做,有如下兩種模式:

  1. 完整重同步:用於初次複製,執行步驟與SYNC基本一致。 PSYNC ? -1
  2. 部分重同步:用於斷線重連後的重複制,在條件容許的狀況下,只須要將斷開期間主服務器的寫命令發送給從服務器 。PSYNC runid offset

如下是執行部分重同步時的通訊過程

部分重同步的工做原理

部分重同步主要由三個部分組成

  1. 主服務器的複製偏移量和從服務器的複製偏移量
  2. 主服務器的複製積壓緩衝區
  3. 服務器的運行ID

複製偏移量

每個服務器都會分別維護一個複製偏移量:

  1. 主服務每次向從服務器傳播N個字節的數據(寫命令)時,就將本身的複製偏移量加N
  2. 從服務每次收到主服務器傳播的N個字節的數據(寫命令)時,就將本身的複製偏移量加N

那麼經過對比主從服務器的複製偏移量就能夠知道

  1. 它們目前的狀態是否一致
  2. 它們之間缺失了多少數據

複製積壓緩衝區

經過複製偏移量能夠知道主從服務器之間缺失了多少數據,那麼缺失的數據是什麼?要去哪裏找回來呢?

這裏就用上了複製積壓緩衝區了

當主服務器進行命令傳播時,它不只將寫命令發送給全部從服務器,還會將寫命令放進一個固定長度的先進先出的隊列裏,這個隊列就是複製積壓緩衝區(默認大小是1MB)

當從服務器重連後,從服務器經過PSYNC命令將本身的複製偏移量發送給主服務器

  1. 若是從服務器複製偏移量以後的數據還在複製積壓緩衝區中,那麼進行部分重同步的操做
  2. 若是從服務器複製偏移量以後的數據不在複製積壓緩衝區中,那麼進行完整重同步的操做

:::tip

如何調整複製積壓緩衝區的大小

經過redis.conf中的repl-backlog-size進行調整

通常調整爲 2 * 斷線重連所需的平均秒數 * 主服務器每秒產生的寫命令數量

:::

服務器運行ID

:::tip

每一個Redis服務器都擁有本身的運行ID

運行ID由服務器啓動時生成,由40個隨機的十六進制字符組成

:::

初次複製時,從服務器會保存主服務器的運行ID

當從服務器斷線重連時,從服務器將這個運行ID發送給主服務器:

  1. 若是與主服務器的運行ID相同,則說明斷線前複製的就是當前鏈接的主服務器,主服務器能夠根據條件嘗試進行部分重同步
  2. 若是與主服務器的運行ID不一樣,則說明斷線前複製的不是當前鏈接的主服務器,主服務器將對從服務器進行完整重同步

PSYNC執行時可能趕上的狀況

從服務器執行SLAVEOF的完整過程

  1. 設置主服務器的地址和端口
  2. 與主服務器創建套接字鏈接
  3. 發送PING命令
  4. 身份驗證
  5. 向主服務器發送從服務器端口信息 REPLCONF listening-port <port-number >
  6. 同步
  7. 命令傳播

心跳檢測

:::tip

在命令傳播階段,從服務器默認一秒一次的速率,向主服務器發送指令

REPLCONF ACK <replication_offset>

其中replication_offset時從服務器當前的複製偏移量

:::

發送REPLCONF ACK命令主要由三個做用:

  1. 檢測主從服務器的鏈接狀態
  2. 輔助實現min-slaves配置選項
  3. 檢測命令丟失

參考

  1. Redis設計與實現
相關文章
相關標籤/搜索