主從復制
這是《Redis設計與實作》系列的文章,系列導航:Redis設計與實作筆記
SLAVEOF
新舊復制功能
舊版復制功能
舊版復制功能的實作為 同步 和 命令傳播:
當剛連上Master時,要做一次全同步:
sequenceDiagram participant Slave participant Master Slave->>Master: SYNC Master->>Master: BGSAVE Master->>Master: 記錄此時的命令到緩沖區中 Master->>Slave: 發送RDB Master->>Slave: 發送命令緩沖區中的命令之所以要用到緩沖區是因為,在主節點進行 BGSAVE 的程序中如果有命令執行,那么我們要把這些命令也記錄下來,
之后,主從節點之間只用 命令傳播 就可以做到同步了,也就是說主節點執行什么命令,從節點跟著執行,(當然,一些隨機、時間類的函式會直接轉換成定值)
舊版復制的缺陷
如果從節點斷線后重新連接,舊版復制功能的效率很低,因為為了讓從服務器補足一小部分的確實卻要進行一次 SYNC 命令,
為什么低效:
- 主節點 BGSAVE 要消耗大量的CPU、記憶體、IO資源
- 主節點發送需要消耗網路資源
- 從節點需要載入,且載入期間處于阻塞狀態
新版復制功能
用 PSYNC 命令代替 SYNC,
PSYNC 具有 完整重同步 和 部分重同步 兩種模式,分別針對初次同步和重新同步兩種場景,
復制功能的實作
復制的實作
復制的一些具體的細節,當進行復制時:
-
從服務器設定主服務器的地址和埠
struct redisServer{ //... char *masterhost; int masterport; //... } -
建立套接字連接,并關聯一個專門處理復制作業的檔案事件處理器
-
發送 PING 命令,檢查套接字和主服務器的狀態是否正常

-
身份驗證,主從必須配置一致且密碼正確(如果有)才能通過驗證
-
發送埠資訊:主節點也得知道給從節點的哪個埠發訊息,不是么
-
同步:干正事兒嘍
這里書上說:
- 在同步操作執行之前,只有從服務器是主服務器的客戶端,但是在執行同步操作之后,主服務器也會成為從服務器的客戶端,
- 正是因為主服務成為了從服務器的客戶端,所以主服務器才能通過發送寫命令來改變從服務器的資料庫狀態,
我想了想,似乎一般確實都是客戶端改變服務端的資料的,所以這么說倒也在理,但是服務端不是也可以給客戶端發送資料么?所以這里可能和 Redis 的具體實作有關?
-
命令傳播:進入了第二個階段
如何部分重同步
要關注的三個部分:
-
復制偏移量:主從服務器都有復制偏移量,通過這個值判斷主從是否處于一致狀態
-
主服務器的復制積壓緩沖區:保存執行命令的歷史記錄
一個固定長度(默認1MB)的 FIFO 的佇列,當主從不一致時可以計算并從中獲取缺少的命令,
由于固定長度,所以如果缺的多了就只能進行完整重同步了,
大小一般設為 斷連平均時間 * 每秒的命令數,安全起見再乘以2,
-
服務器的運行 ID
畢竟只有 ID 一致同步才有意義,否則說明換主人了,那還是全同步吧
PSYNC的邏輯
graph LR; S(接收到SLAVEOF命令) --> A{第一次復制?} A --Y--> A1[發送PSYNC ? -1] --> E1(回傳+FULLRESYNC <runid> <offset>) A --N--> A2[發送PSYNC <runid> <offset>] --> B{主服務器回傳 +CONTINUE} B --N--> E1 B --Y--> E2[執行部分重同步]主要是判斷 是否是第一次復制 、 是否是同一個主服務器,從而決定是部分重同步還是全同步,
上圖沒有展示的是,如果主服務器不支持 PSYNC,則回傳 -ERR
心跳檢測
心跳檢測:在命令傳播階段,從服務器默認每秒發送一次心跳:REPLCONF ACK <replication_offset>,
作用有三:
-
檢測主從服務器的網路狀態
-
輔助實作 min-slaves 配置選項
min-slaves-to-write、min-slaves-max-lag 可以防止發生腦裂現象
-
通過 offset 檢測命令是否丟失
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/467100.html
標籤:NoSQL
