單機跑久了總會遇到機器掛掉的時候,就算有 AOF 跟 RDB,重開機還是有一段時間不能服務。加上單機讀寫效能總是有天花板。
為了解決這些問題,Redis 提供了主從複製(Master-Slave Replication)。
今天先拆主從複製的流程,尤其是第一次同步時會用到的 SYNC 協定。
Redis 主從複製大致分成兩段:第一次把資料整包同步過去的全量同步(Full Resynchronization),以及後續持續追寫入的增量同步(Incremental Propagation)。
全量同步(Full Resynchronization)
1. Slave 執行 SLAVEOF host port
2. Slave → Master:建立 TCP 連線並發送 PING
3. Master → Slave:回應 PONG(握手成功)
4. Slave → Master:發送 SYNC 命令
5. Master:生成當前記憶體的 RDB 快照
6. Master → Slave:傳送 RDB 二進位數據包
7. Slave:清空舊數據,加載 RDB 檔案恢復狀態
增量同步(Incremental Propagation,Loop)
8. Master:開始收集所有後續寫操作指令
9. Master → Slave:傳播寫指令(Replication Stream)
10. Slave:重播執行指令,保持數據一致
當一個從節點(Slave)第一次連接到主節點(Master),或者與主節點斷開時間過長無法進行部分同步時,會觸發全量同步:
SYNC 指令。SYNC 後,在背景執行 bgsave,生成一份目前的 RDB 二進位快照。bgsave 那個瞬間完全一致。在全量同步期間與完成後,主節點接收到的所有寫入指令(如 SET, DEL),都會在本地執行成功的同時,將該寫指令的 RESP byte stream,發送給所有連接中的從節點。
從節點收到指令後直接在自己的資料庫中 replay 執行。這就是 Replication Stream (複製流)。
在 Redis 主從複製中,資料流是單向的——只能從 Master 流向 Slave。
這樣做是為了讓資料流向保持單純。如果 Slave 也能寫入,兩邊同時改同一個 Key 時就得處理衝突。這邊老實說一開始我也想過雙向同步,但光想解衝突就知道會寫出一堆 Bug,還是單向傳播省事又安全。
來測一下我們的 AUTH 有沒有發揮作用。
# 在 redis-cli 連線到設定了密碼的伺服器
$ redis-cli
> GET mykey
# 預期回覆:(error) NOAUTH Authentication required.
> AUTH mypassword
# 預期回覆:OK
> GET mykey
# 預期回覆:(nil) 或是資料
沒密碼連看都不給看,這下安全多了!
今天先把主從複製的全量同步和增量同步流程摸熟,也釐清 SYNC 在整個流程裡的位置。
明天就來動手寫從節點的背景同步和 RDB 載入,讓它自己連上主節點把資料拖回來,感覺會有點挑戰。