1. 程式人生 > 其它 >《Redis設計與實現》讀書筆記(二十五) ——Redis主從複製具體過程

《Redis設計與實現》讀書筆記(二十五) ——Redis主從複製具體過程

《Redis設計與實現》讀書筆記(二十五)

——Redis主從複製具體過程

(原創內容,轉載請註明來源,謝謝)

一、PSYNC命令執行過程

psync是新版redis複製使用的命令,下面討論其執行過程。

psync命令呼叫方法有兩種:

1)從伺服器以前如果沒有複製過任何主伺服器,或者執行過slaveof no one命令,則第一次複製會發送psync ? -1命令,表示強制要求主伺服器進行完全重同步。

2)如果從伺服器以前複製過主伺服器,則會發送psync <runid> <offset>,將主伺服器的執行ID和從伺服器當前自身複製偏移量傳送給主伺服器,由主伺服器判斷是要部分重同步還是完全重同步。

主伺服器的回覆有三種:

1)+fullresync<runid> <offset>,則表示要完全重同步。從伺服器會記錄runid,作為下次斷線重連發送的內容;將offset作為從伺服器當前的偏移量。

2)+continue,表示部分重同步,從伺服器只需要等待主伺服器將缺少的部分發送過來,再進行同步即可。

3)-err,表示主伺服器版本低於2.8,不支援psync,則從伺服器會再發送sync命令,進行完整同步。

如下圖所示:

二、複製的實現

複製採用的命令是slaveof<masterip> <masterport>,詳細實現步驟如下:

1、設定主伺服器的ip和埠

執行上述命令後,從伺服器會將主伺服器的ip和埠設定在自身redisServer結構體中的屬性中,ip設定到char陣列的masterhost名稱,port設定到int的masterport。

設定完成後,從伺服器會向客戶端返回OK。

2、建立套接字連線

執行slaveof命令後,從伺服器將根據ip和埠號,與主伺服器建立套接字連線。

從伺服器成功連線主伺服器後,從伺服器將為該連線專門建立一個用於複製工作的檔案事件處理器,這個處理器接收rdb檔案、處理主伺服器的命令傳播等。

主伺服器接收到從伺服器的套接字連線後,為套接字建立相應的狀態,並將從伺服器看作一個連線到主伺服器的客戶端,此時從伺服器同時具有客戶端和伺服器兩個身份,從伺服器可以向主伺服器傳送命令請求,主伺服器會向從伺服器傳送命令回覆。

3、傳送PING命令

從伺服器連線上主伺服器後,會先發送一個PING命令,具有兩個作用:

1)檢查主從伺服器的套接字讀寫狀態是否正常。

2)檢查主伺服器當前可以正常處理請求。

從伺服器會收到主伺服器的三種回覆的一種:

1)主伺服器向從伺服器回覆內容,從伺服器不能在規定時限內讀取命令內容,則認為主從伺服器當前網路不佳,無法處理後續的同步工作。從伺服器會斷開套接字,再自動重連並重新建立向主伺服器的套接字。

2)主伺服器向從伺服器回覆一個錯誤,表示主伺服器當前無法處理從伺服器的請求,從伺服器會斷開並重新建立向主伺服器的套接字。

3)從伺服器接收到主伺服器的PONG回覆,表示主從伺服器網路正常,主伺服器當前可以處理從伺服器的命令,則從伺服器會進入後續的步驟。

PING命令判斷流程如下:

4、身份驗證

從伺服器收到PONG後,將進入身份驗證階段。

如果其有設定masterauth選項,則開始身份驗證,否則不驗證。如果需要驗證,則從伺服器接下來會給主伺服器傳送auth命令,並帶上masterauth選項的值作為引數。

身份驗證階段會有以下幾個結果:

1)主伺服器沒有設定requirepass選項,從伺服器也沒有設定masterauth,則跳過身份驗證。

2)主伺服器沒有設定requirepass,而從伺服器設定masterauth,會報noauth錯誤。

3)主伺服器設定requirepass,而從伺服器沒有設定masterauth,會報nopassword is set錯誤。

所有錯誤都會終止當前的複製工作,並從建立套接字開始重新執行復制,直到驗證通過。

5、傳送埠資訊

身份驗證通過後,從伺服器會向主伺服器傳送replconf listening-port <port-number>命令,向從伺服器監聽埠號。

主伺服器接收到埠號後,會將其記錄在對應客戶端redisClient結構體中的屬性中,型別是int,名稱是slave-listening-port。該屬性目前唯一作用是主伺服器執行info replication命令時,打印出從伺服器的埠號。

6、同步

完成上述步驟後,從伺服器會發送psync給主伺服器。

在同步操作之前,只有從伺服器是主伺服器的客戶端,而同步之後,主伺服器也是從伺服器的客戶端,即互為客戶端。

這樣主伺服器才可以將儲存在緩衝區的寫命令(完整重同步)、儲存在複製積壓緩衝區(部分重同步)中的寫命令發給從伺服器。

7、命令傳播

完成同步後,後續只要主伺服器狀態改變,都會給從伺服器傳送寫命令,從伺服器執行寫命令後,就保證主從一致性。

六、心跳檢測

在命令傳播階段,從伺服器預設每秒1次的頻率,向主伺服器傳送如下命令:

         replconfack <replication_offset>

replication_offset是從伺服器的偏移量,傳送此命令有三個作用:

1、檢測主從伺服器網路狀態。

如果主伺服器超過1秒沒有接收到從伺服器的replconfack命令,表示主從間的連接出問題了。info replication命令可以檢視從伺服器最後一次傳送該命令的時間,屬性值是lag,即lag大於1表示出問題了。

2、輔助實現min-slaves選項。

redis的min-slaves-to-write和min-slaves-max-lag兩個選項可以在主伺服器不安全的情況下,防止執行客戶端的寫命令。

例如min-slaves-to-write3,min-slaves-max-lag 10,表示少於3個從伺服器或三個從伺服器的延遲(lag)值都大於等於10秒,主伺服器將拒絕執行寫命令。

3、檢測命令丟失。

由於每次傳送replconfack命令,都帶上當前的偏移量,這樣就可以保證如果主伺服器傳送給從伺服器的命令傳播,由於網路問題導致資料丟失的問題能1秒內被主伺服器發現。主伺服器發現後,會將相應偏移量的內容從複製積壓緩衝區取出,併發送給從伺服器。

replconfack命令和複製積壓緩衝區的概念,都是從redis2.8開始有的,在此之前的版本,主伺服器無法發現從伺服器的資料丟失。因為使用主從的情況下,為了資料一致性,儘量使用2.8以上版本的redis。

七、總結

1、redis2.8之前的版本,主從複製中,每次從伺服器斷線重連後,都要進行整個伺服器的同步;而2.8版本開始,在一定情況下,可以實現部分重同步。

2、部分重同步是通過複製偏移量來判斷是否需要,通過複製積壓緩衝區來取出偏移量範圍內的全部資料,通過從伺服器傳送給主伺服器的主伺服器執行ID來判斷上一次從伺服器連線的主伺服器與此次連線是否一致。

3、如果複製偏移量超出複製積壓緩衝區,或者從伺服器傳送的執行ID和主伺服器當前執行ID不一致,或者主伺服器的redis版本在2.8之前,都會進行完全重同步。

4、複製剛開始,從伺服器是客戶端,到開始同步的時候,主從伺服器互為客戶端。

5、複製過程包括:從伺服器設定主伺服器ip和埠;建立套接字;傳送PING命令;身份驗證;傳送埠資訊;同步;命令傳播。

6、當主從進入命令傳播階段,從伺服器每秒(時間可配置)給主伺服器傳送一條命令,內容是當前從伺服器的偏移量,以確保主從網路正常,並且如果偏移量和主伺服器當前的不一致,也便於主伺服器再次傳送偏移資料,以保證主從資料一致性。

7、由於效率以及資料一致性,如果要採用主從同步,建議使用redis2.8或以上的版本。

——written by linhxx 2017.09.12