標籤:redis 高效能分布式緩衝 主從複製 sync psync
為了提供整個緩衝的可用性,可以給主伺服器添加待命伺服器,即從伺服器。通過SLAVEOF命令把當前伺服器設定成某台伺服器的從伺服器。
老版本同步過程
舊版本(2.8之前)主從伺服器資料同步過程如下:
- 從伺服器向主伺服器發送SYNC命令。
- 主伺服器接收到SYNC命令後調用BGSAVE命令產生一個RDB檔案,在此過程中用戶端對主伺服器的修改命令存放在一個緩衝區中。
- 主伺服器把產生的RDB檔案發送給從伺服器,從伺服器通過載入該RDB檔案更新資料庫狀態。
- 主伺服器把緩衝區中的命令同步到從伺服器,從伺服器執行這些命令更新資料庫。
老版本在SYNC命令同步處理有非常大的效能缺陷,在主從伺服器斷線重連之後執行同步動作時,也會產生完整的RDB檔案並且發送到從伺服器載入,但是主從伺服器的資料庫狀態在斷線前基本上是一致的,不一致的部分只有斷線後主伺服器執行那一部分修改資料庫的命令,所以這時候SYNC命令就顯得非常浪費,因為產生RDB檔案時一個非常消耗CPU、記憶體和IO資源的過程,而發送RDB檔案到從伺服器也會佔用大量的網路頻寬資源,從伺服器在載入RDB檔案的過程中也阻塞不會相應任何命令,所以大部分情況下執行SYNC命令是沒有必要也是非常不合理的。
為瞭解決2.8之前版本SYNC命令的效能問題,2.8版本設計了一個新的命令PSYNC,PSYNC命令分為完整重同步和部分重同步,完整重同步過程用於從伺服器初始化時初次複製的情況和SYNC命令基本一致,PSYNC則用於斷線後重新複製,在條件允許的情況下,它不會產生RDB檔案,而是給從伺服器回複一個+Continue表示執行部分重同步,並且把從伺服器斷線後主伺服器執行的修改資料庫的命令發送到從伺服器,從伺服器執行這些命令同步資料庫。
部分重同步功能由下面幾個部分構成:
- 主伺服器的複製位移量和從伺服器的複製位移量:當主伺服器在向從伺服器進行命令同步時,主伺服器和從伺服器會各自記錄一個複製位移量,當主從伺服器的資料庫狀態一致時這兩個複製位移量是相同的,如果這兩個位移量不一致說明當前主從伺服器的狀態不一致。
- 主伺服器的複製積壓緩衝區:複製積壓緩衝區是一個固定大小的FIFO隊列,當隊列已滿時會彈出最早插入的資料,在主伺服器進行命令傳播時會同時把命令放到緩衝區中,緩衝區包含兩部分資料,位移量和位元組。在進行複製時從伺服器會將位移量上報到主伺服器,主服務檢查當前位移量是否還存在緩衝區中,如果存在進行部分重同步,如果不存在進行完整重同步。因為這個積壓緩衝區是一個固定大小的隊列,所以當從伺服器長時間斷線時,從伺服器的複製位移量很可能已不再緩衝區中,這時候只能進行完整重同步。
- 伺服器的運行ID:初次同步時主伺服器會把ID發給從伺服器,從伺服器儲存主伺服器ID,當斷線重連後,會把之前儲存的主伺服器ID上報給主伺服器,主伺服器檢查從伺服器之前複製的主伺服器ID是否和自己的ID相同,如果相同,執行部分重同步,如果不同說明從伺服器之前記錄的狀態不是當前主伺服器,這時候需要執行完整重同步。
PSYNC命令實現初始複製或者之前執行過SLAVEOF no one命令,執行完整重同步:發送PSYNC ? -1命令到主伺服器。
如果從伺服器已經複製過某個主伺服器,在開始新複製時向主伺服器發送PSYNC <runid> <offset>命令,runid是上次複製的主伺服器id,offset是從伺服器的複製位移量,主伺服器會根據這個兩個參數來決定做哪種同步,判斷伺服器id是否和本機相同,複製位移量是否在緩衝區中,主伺服器有三種回複:
- 回複+FULLRESYNC <runid> <offset>執行完整重同步,從伺服器把offset當做初始複製位移量
- 回複+CONTINUE,表示執行部分重同步,從伺服器等待主伺服器發送缺少的資料
- 回複-ERR,表示主伺服器版本低於2.8,不支援PSYNC命令
新版本同步過程2.8及以後版本複製過程:
- 設定主伺服器地址和連接埠,通過調用SAVEOF <master_ip> <master_port>命令。
- 建立通訊端串連。
- 發送PING命令,檢查主從伺服器是否能夠正常處理命令。
- 身分識別驗證,從伺服器設定了masterauth並且主伺服器設定了requirepass是需要進行身分識別驗證。這兩個選項要麼都設定要麼都不設定,如果只設定了一個從伺服器向主伺服器發送命令時會報錯。
- 傳送埠資訊,通過執行命令REPLCONF listening-port <port-number>,向主伺服器發送從伺服器的監聽連接埠號碼。
- 同步,從伺服器向主伺服器發送PSYNC命令。
- 命令傳播,完成同步之後主伺服器會把之後執行的寫命令傳播到從伺服器保證主從伺服器的狀態一致。
心跳檢測在命令傳播階段,從伺服器預設每秒一次的頻率向主伺服器發送命令:REPLCONF ACK <replication_offset>,replication_offset是從伺服器的複製位移量,該命令有三個作用:
- 檢測從伺服器的網路連接狀態,檢測主從伺服器串連是否正常,如果主伺服器超過一定時間沒有收到從伺服器的REPLCONF ACK 命令,那麼它們的串連可能出了問題。
- 輔助實現min-slaves選項,min-slaves-to-write和min-slaves-max-lag兩個選項可以防止主伺服器在不安全的情況下執行寫命令,min-slaves-to-write 3 min-slaves-max-lag 10 表示如果從伺服器少於3個,或者3個從伺服器的延遲都大於10秒時,主伺服器拒絕寫命令。
- 檢測命令丟失,主伺服器接收到從伺服器的REPLCONF ACK 命令之後會檢查從伺服器的位移量是否和主伺服器的一致,如果不一致會把積壓緩衝區中的從伺服器位移量後面的命令發送到從伺服器。
《Redis設計與實現》學習筆記-主從複製