Redis設計與實現之複製

Redis中用戶通過執行slaveof命令或者設置slaveof選項,讓一個服務器去複製另一個服務器。被複制的稱爲主服務器(master),複製的稱爲從服務器(slave)。

1,舊版複製功能及其缺點

redis的複製功能,分爲同步和命令傳播兩個操作:
同步:將從服務器的狀態更新至主服務器目前所處的狀態
命令傳播:主服務器對數據庫狀態進行修改導致主從服務器狀態不一致時,讓主從服務器數據庫恢復至統一狀態。

1,1同步

當客戶端向服務器發送slaveof命令,要求從服務器複製主服務器時,從服務器要先執行同步操作。
同步操作是從服務器向主服務器發送sync命令完成,執行步驟:
1)從服務器向主服務器發送sync命令
2)收到sync的主服務器開始執行bgsave,在後臺生成一個RDB文件,並使用一個緩衝區記錄當前開始服務器執行的所有寫命令
3)bgsave執行完畢之後,主服務器將bgsave命令生成的RDB文件發送給從服務器。從服務器使用RDB文件,更新數據庫到執行bgsave時的狀態
4)主服務器將記錄在緩衝區中的所有寫命令發送給從服務器,從服務器執行這些命令,將數據庫更新到主服務器當前的狀態

1,2命令傳播

同步操作完成之後,主從服務器達到的數據庫一致狀態並不是一成不變的。當主服務器再執行寫命令,就會再次導致主從不一致這個時候需要使用命令傳播操作:主服務器將導致主從不一致的寫命令發送給從服務器執行,再次達到主從一致狀態。

1,3舊版複製功能缺點

Redis中的複製有初次複製和斷線後重複製兩種。對於初次複製,舊版複製功能可以很好的完成。但是對於斷線後複製,舊版複製功能會效率比較低,原因是斷線後重複製只需要執行斷線期間執行的寫命令並不需要重新生成RDB文件,但是舊版複製功能會再次使主服務器執行非常耗費資源的bgsave從而導致效率低下。

2,新版複製功能

新版複製功能解決了舊版複製處理斷線重複制遇到的問題,使用psync代替sync命令,將複製分爲完整重同步和部分重同步兩個模式:
完整重同步:適用於初次複製的情況與sync的執行過程一樣。
部分重同步:適用於斷線重複制的情況,從服務器斷線後重新連接主服務器,並請求同步。主服務器根據情況將斷開期間執行的寫命令發給從服務器,而不必重新生成RDB文件。
部分重同步功能的實現由三個部分構成:
1,主從服務器各自維護的複製偏移量
2,主服務器的複製積壓緩衝區
3,服務器的運行ID
複製偏移量:主從服務器各自維護的複製偏移量表示當前複製了多少字節數據。主服務器想從服務器傳播N個字節數據時,就將自己的複製偏移量加N。從服務器每次從主服務器接受N字節的數據,也將自己的複製偏移量加N。主從雙方通過複製偏移量判斷狀態是否一致。
複製積壓緩衝區:由主服務器維護的一個固定長度的先進先出隊列,默認大小1MB。因爲是固定大小,所以當緩衝區滿的時候舊元素就會被彈出給新元素留出空間。主服務器運行期間複製積壓緩衝區會根據每秒產生的命令數和服務器斷線重連的時間間隔進行調整。不小於2*second*write_size_per_second
當主服務器進行命令傳播的時候,不僅會將寫命令發送給所有的從服務器,也會寫入複製積壓緩衝區中。因此複製積壓緩衝區中保存了一部分最近傳播的寫命令,並且複製積壓緩衝區也會爲隊列中的每一個字節記錄相應的複製偏移量。當從服務器再次連上主服務器時,發送psync命令將自己的offset發給主服務器,主服務根據offset來決定對其執行哪種同步操作:
1)如果offset偏移量後的數據還在複製積壓緩衝區中,就執行部分重同步操作,將需要的命令發送給從服務器執行
2)如果offset偏移量後的數據不在複製積壓緩衝區中,就執行完整重同步操作。
服務器運行ID:每個Redis服務器(所有)都會在啓動的時候自動生成一個40個隨機的16進制字符的運行ID。
從服務器進行初次複製的時候,主服務器會將自己的ID發送給從服務器,從服務器會保存主服務器ID。當從服務器斷線並重新連接到一個主服務器時,從服務器會將之前保存的ID發送給當前的主服務器:
1)如果從服務器發送的ID和當前主服務器ID相同,可以嘗試部分重同步
2)兩個ID不同,說明之前鏈接的不是同一個服務器,要執行完整重同步
psync的執行過程如下:
這裏寫圖片描述

3,複製功能的實現

使用slaveof 命令,我們讓一個從服務器去複製主服務器,詳細步驟如下:

3.1,設置主服務器ip和port

從服務器收到命令之後,會在redisServer的masterhost和masterport屬性中設置master的ip和port,然後向發送slaveof命令的客戶端返回ok,表示複製命令已接收,但現在真正的複製工作纔開始。

3.2,建立套接字

從服務器向主服務器建立套接字用於命令請求與命令回覆如RDB文件接收等。此時,從服務器是主服務器的客戶端。

3.3,發送ping命令

套接字建立之後,從服務器向主服務器發送一個ping命令,主要用於檢查套接字的讀寫狀態是否正常以及主服務器能否正常處理命令請求。
if 主服務器返回pong
表示一切正常,繼續執行下一個步驟
else if 讀取ping命令超時 or 主服務器返回錯誤
斷開重連主服務器

3.4,身份驗證

如果從服務器設置了masterauth選項就進行身份驗證,否則不驗證。如果驗證就向主服務器發送auth命令,參數爲masterauth選項中獲得的值。
這裏寫圖片描述

3.5,發送端口信息

從服務器執行replconf listening-port ,向主服務器發送從服務器的監聽端口號。主服務器會將其記錄在redisClint相應字段中。

3.6,執行同步

從服務器向主服務器發送psync命令,執行同步操作,將自己的數據更新至主服務器相同的狀態。因爲同步過程中及之後,雙方都要向對方發送命令所以主從服務器之間互爲客戶端。

3.7,命令傳播

完成同步之後,主從服務器就進入了命令傳播階段,此時主服務器一直將自己執行的寫命令發送給從服務器執行,雙方就可以保持一致狀態。

3.4,心跳檢測

命令傳播階段,從服務器每秒一次向主服務器發送命令:replconf ack #複製偏移量,然後等待迴應。
作用有三個:
1,檢測主從之間的網絡連接狀態
2,輔助實現min-slaves選項,爲防止主服務器在不安全的情況下執行寫命令,當從服務器數量少於min-slaves-to-write所指定的或者服務器的延遲都大於或等於min-slaves-max-lag時,主服務器將拒絕執行寫命令。
3,檢測寫命令丟失,通過驗證offset是否一致,保證雙方的狀態一致。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章