文章目錄
- 一、主從復制的概念
- 二、全量復制(完整重同步)
- 三、增量復制(部分重同步)
- 1. 增量復制的核心思想
- 2. 增量復制的實現
- 3. 復制偏移量(replicationoffset)
- 4. 復制積壓緩沖區(replicationbacklog)
- 4.1 緩沖區隊列內容
- 4.2 緩沖區隊列更新
- 4.3 同步方式判斷
- 4.4 緩沖區配置優化
- 5. 服務器的運行ID(runID)
- 四、心跳檢測
- 五、關鍵配置參數
- 總結
Redis 為保證高可用,提供了主從服務器、集群搭建的方案。這樣即使某一個服務器宕機了,Redis 還可以對外提供服務。一般主服務器提供讀寫功能,從服務器只提供讀功能,為保證主從服務器的讀一致性,需要將主服務器的數據同步到從服務器。以下是關于主從服務器實現數據同步的詳細介紹:
一、主從復制的概念
Redis從2.8版本開始,使用PSYNC命令代替SYNC命令來執行復制時的同步操作。PSYNC指令分兩種同步模式:全量復制(完整重同步) 和 增量復制(部分重同步) 。
Redis 主從服務器在初次連接的時候,會進行一次全量復制,當全量復制完成后會進行增量復制。slave 服務器在數據同步過程中會優先嘗試增量復制,如果不滿足增量復制條件,則發起全量復制。
以下是Redis 在主從復制時選擇兩種模式執行的流程:
二、全量復制(完整重同步)
Redis 全量復制使用PSYNC命令,通過讓主服務器創建并發送RDB文件,以及向從服務器發送保存在緩沖區里面的寫命令來進行同步。
以下是Redis全量復制的執行步驟:
- 從服務器先判斷是否為初次復制:
- 如果是初次復制,則通知主服務器進行全量復制;
- 如果不是初次復制,則通知主服務器進行部分復制,但是主服務器判斷無法進行部分復制,最后主服務器會自己選擇執行全量復制。
- 主服務器收到全量復制命令后,執行BGSAVE命令,在后臺生成一個RDB文件,并使用一個緩沖區記錄從現在開始執行的所有寫命令。
- 當主服務器的BGSAVE命令執行完畢時,主服務器會將BGSAVE命令生成的RDB文件發送給從服務器,從服務器接收并載入這個RDB文件,將自己的數據庫狀態更新至主服務器執行BGSAVE命令時的數據庫狀態。
- 主服務器將記錄在緩沖區里面的所有寫命令發送給從服務器,從服務器執行這些寫命令,將自己的數據庫狀態更新至主服務器數據庫當前所處的狀態。
- 如果從服務器開啟了AOF,則會觸發bgrewriteaof的執行,從而保證AOF文件更新至主服務器數據庫的最新狀態。
三、增量復制(部分重同步)
Redis 增量復制主要目的是解決主從服務器斷線重連后的 增量數據,避免全量復制的開銷。
1. 增量復制的核心思想
當從服務器在斷線后重新連接主服務器時,主服務器可以將主從服務器連接斷開期間執行的寫命令發送給從服務器,從服務器只要接收并執行這些寫命令,就可以將數據庫更新至主服務器當前所處的狀態。
2. 增量復制的實現
增量復制同步功能的實現由以下三個部分構成:
- 主服務器的復制偏移量(replicationoffset)和從服務器的復制偏移量。
- 主服務器的復制積壓緩沖區(replicationbacklog)。
- 服務器的運行ID(runID)。
3. 復制偏移量(replicationoffset)
執行復制的主服務器和從服務器會分別維護一個復制偏移量:
- 主服務器每次向從服務器傳播N個字節的數據時,就將自己的復制偏移量的值加上N。
- 從服務器每次收到主服務器傳播來的N個字節的數據時,就將自己的復制偏移量的值加上N。
假設當前主從服務器的復制偏移量的值都為10086,如果這時主服務器向三個從服務器傳播長度為33字節的數據,那么主服務器的復制偏移量將更新為10086+33=10119,而三個從服務器在接收到主服務器傳播的數據之后,也會將復制偏移量更新為10119。
主從服務器通過維護復制偏移量,比較復制偏移量的大小,就可以判斷主從服務器是否處于一致狀態:
- 如果主從服務器處于一致狀態,那么主從服務器兩者的偏移量總是相同的。
- 相反,如果主從服務器兩者的偏移量并不相同,那么說明主從服務器并未處于一致狀態。
4. 復制積壓緩沖區(replicationbacklog)
復制積壓緩沖區是由主服務器維護的一個固定長度(fixed-size)先進先出(FIFO)隊列,默認大小為1MB。
4.1 緩沖區隊列內容
主服務器的復制積壓緩沖區里面會保存著一部分最近傳播的寫命令,并且復制積壓緩沖區會為隊列中的每個字節記錄相應的復制偏移量。
4.2 緩沖區隊列更新
當主服務器進行命令傳播時,它不僅會將寫命令發送給所有從服務器,還會將寫命令入隊到復制積壓緩沖區里面。由于隊列是固定長度,所以隊列內保存的命令在不斷的更新。
如果主從服務器斷開時間很久,主從服務器的復制偏移量可能會相差很大,從服務器的復制偏移量可能已經不再緩沖區了。
4.3 同步方式判斷
當從服務器重新連上主服務器時,從服務器會通過PSYNC命令將自己的復制偏移量offset發送給主服務器,主服務器會根據這個復制偏移量來決定對從服務器執行何種同步操作:
- 如果offset偏移量之后的數據(也即是偏移量offset+1開始的數據)仍然存在于復制積壓緩沖區里面,那么主服務器將對從服務器執行增量復制操作。
- 相反,如果offset偏移量之后的數據已經不存在于復制積壓緩沖區,那么主服務器將對從服務器執行全量復制操作。
4.4 緩沖區配置優化
Redis為復制積壓緩沖區設置的默認大小為1MB,如果主服務器需要執行大量寫命令,又或者主從服務器斷線后重連接所需的時間比較長,那么這個大小也許并不合適。如果復制積壓緩沖區的大小設置得不恰當,那么PSYNC命令的復制重同步模式就不能正常發揮作用,因此,正確估算和設置復制積壓緩沖區的大小非常重要。
優化配置復制積壓緩沖區大小repl-backlog-size
的值,該值最小大小可以根據公式 2*second*writesizeper_second
來計算:
- second為從服務器斷線后重新連接上主服務器所需的平均時間(以秒計算)。
- write_size_per_second則是主服務器平均每秒產生的寫命令數據量(協議格式的寫命令的長度總和)。
5. 服務器的運行ID(runID)
除了復制偏移量和復制積壓緩沖區之外,實現增量復制還需要用到服務器運行ID(runID):
- 每個Redis服務器,不論主服務器還是從服務,都會有自己的運行ID。
- 運行ID在服務器啟動時自動生成,由40個隨機的十六進制字符組成,例如53b9b28df8042fdc9ab5e3fcbbbabff1d5dce2b3。
- 當從服務器對主服務器進行初次復制時,主服務器會將自己的運行ID傳送給從服務器,而從服務器則會將這個運行ID保存起來。
- 當從服務器斷線并重新連上一個主服務器時,從服務器將向當前連接的主服務器發送之前保存的運行ID:
- 如果從服務器保存的運行ID和當前連接的主服務器的運行ID相同,那么說明從服務器斷線之前復制的就是當前連接的這個主服務器,主服務器可以繼續嘗試執行增量復制操作。
- 相反地,如果從服務器保存的運行ID和當前連接的主服務器的運行ID并不相同,那么說明從服務器斷線之前復制的主服務器并不是當前連接的這個主服務器,主服務器將對從服務器執行全量復制操作。
四、心跳檢測
在命令傳播階段,從服務器默認會以每秒一次的頻率,向主服務器發送命令:
# replication_offset是從服務器當前的復制偏移量。
REPLCONF ACK <replication_offset>
從服務器發送REPLCONF ACK命令對于主從服務器有三個作用:
- 檢測主從服務器的網絡連接狀態:
- 如果主服務器超過一秒鐘沒有收到從服務器發來的REPLCONF ACK命令,那么主服務器就知道主從服務器之間的連接出現問題了。
- 通過向主服務器發送INFO replication命令,在列出的從服務器列表的lag一欄中,我們可以看到相應從服務器最后一次向主服務器發送REPLCONF ACK命令距離現在過了多少秒。
- 輔助實現min-slaves選項:
- Redis的min-slaves-to-write和min-slaves-max-lag兩個選項可以防止主服務器在不安全的情況下執行寫命令。
- 比如我們向主服務器設置min-slaves-to-write=3和min-slaves-max-lag=10,那么在從服務器的數量少于3個,或者三個從服務器的延遲(lag)值都大于或等于10秒時,主服務器將拒絕執行寫命令,這里的延遲值就是上面提到的INFO replication命令的lag值。
- 檢測命令丟失:
- 如果因為網絡故障,主服務器傳播給從服務器的寫命令在半路丟失,那么當從服務器向主服務器發送REPLCONF ACK命令時,主服務器將發覺從服務器當前的復制偏移量少于自己的復制偏移量,然后主服務器就會根據從服務器提交的復制偏移量,在復制積壓緩沖區里面找到從服務器缺少的數據,并將這些數據重新發送給從服務器。
- 注意,主服務器向從服務器補發缺失數據這一操作的原理和增量復制操作的原理非常相似,這兩個操作的區別在于,補發缺失數據操作在主從服務器沒有斷線的情況下執行,而部分重同步操作則在主從服務器斷線并重連之后執行。
五、關鍵配置參數
參數 | 作用 | 推薦值 |
---|---|---|
repl-backlog-size | 調整復制積壓緩沖區大小 | 2 * 網絡延遲 * 每秒寫入量 |
repl-diskless-sync | 啟用無盤復制,減少磁盤 I/O | yes (網絡良好時) |
repl-diskless-sync-delay | 無盤復制延遲時間(秒) | 5 |
client-output-buffer-limit slave | 限制復制緩沖區大小,防止OOM | 512mb 128mb 60 |
repl-timeout | 復制超時時間 | 60s (需大于repl-ping-replica-period ) |
replica-serve-stale-data | 斷線時是否允許從節點響應讀請求 | no |
replicaof <master_ip> <master_port> | 指定主節點地址 | 無 |
總結
Redis主從復制通過全量復制確保初始一致性,增量復制優化持續同步效率,結合復制積壓緩沖區和偏移量跟蹤機制,實現了高效且可靠的數據同步。合理配置參數和監控網絡狀態是優化復制性能的關鍵。