天天看點

redis詳解_Redis 複制過程詳解

Redis 的複制功能分為同步( sync )和指令傳播( command propagate )兩個步驟:

  • 同步用于将從伺服器的資料庫狀态更新至主伺服器目前所處的資料庫狀态。
  • 指令傳播則用于在主伺服器的資料庫狀态被修改,導緻主從伺服器的資料庫狀态出現不一緻時,讓主從伺服器的資料庫重新回到一緻狀态。

同步

Redis 使用 psync 指令完成主從資料同步,同步過程分為:全量複制和部分複制。

全量複制:一般用于初次複制場景,它會把主節點全部資料一次性發送給從節點發送給從節點,當資料量較大時,會對主從節點和網絡造成很大的開銷。

部分複制:用于處理在主從複制中因網絡閃斷等原因造成的網絡丢失場景,當從節點再次連接配接上主節點後,如果條件允許,主節點會補發丢失資料給從節點。因為補發的資料遠遠小于全量資料,可以有效避免全量複制的過高開銷。

psync 指令運作需要以下元件支援:

  • 主從節點各自複制偏移量
  • 主節點複制積壓緩沖區
  • 主節點運作 id

參與複制的從節點都會維護自身複制偏移量。主節點在處理完寫指令後,會把指令的位元組長度做累加記錄,統計在 info replication 中的 masterreploffset 名額中。 從節點在接收到主節點發送的指令後,也會累加記錄自身的偏移量,并且會每秒鐘上報自身的複制偏移量給主節點。 通過對比主從節點的複制偏移量,可以判斷主從節點資料是否一緻。

複制積壓緩沖區是儲存在主節點的一個固定長度的隊列,預設大小為 1MB,當主節點有連接配接的從節點時被建立。主節點響應寫指令時,不但會把指令發送給從節點,還會寫入複制積壓緩沖區中。

複制積壓緩沖區大小有限,隻能儲存最近的複制資料,用于部分複制和複制指令丢失時的資料補救。

每個 Redis 節點啟動後都會動态配置設定一個 40 位的十六進制字元串作為運作 ID。運作 ID 的主要作用是用來唯一辨別 Redis 節點,比如說從節點儲存主節點的運作 ID 來識别自己正在複制的時哪個主節點。

全量同步

redis詳解_Redis 複制過程詳解

slaveof

指令的執行

  • 1) 從節點發送 psync 指令進行資料同步,由于是第一次進行複制,從節點沒有複制偏移量和主節點的運作ID,是以發送的指令時 PSYNC ? -1。
  • 2) 主節點根據 PSYNC ? -1 解析出目前為全量複制,回複 + FULLRESYNC 響應。
  • 3) 從節點接收主節點的響應資料儲存運作 ID 和偏移量 offset。
  • 4) 主節點執行 bgsave 儲存 RDB 檔案到本地,有關 RDB 的知識可以檢視《Redis RDB 持久化詳解》
  • 5) 主節點發送 RDB 檔案給從節點,從節點把接收的 RDB 檔案儲存在本地并直接作為從節點的資料檔案,接收完 RDB 後從節點列印相關日志,可以在日志中檢視主節點發送的資料量。

需要注意,對于資料量較大的主節點,比如生成的 RDB 檔案超過 6GB 以上時要格外小心。如果傳輸 RDB 的時間超過 repl-timeout 所配置的值,從節點将發起接收 RDB 檔案并清理已經下載下傳的臨時檔案,導緻全量複制失敗。

  • 6) 對于主節點開始儲存 RDB 快照到從節點接收完成期間,主節點仍然響應讀指令,是以主節點會把這期間寫指令儲存在複制用戶端緩沖區内,當從節點加載完 RDB 檔案後,主節點再把緩沖區内的資料發送給從節點,保證主從之間資料一緻性。

如果主節點建立和傳輸 RDB 的時間過長,可能會出現主節點複制用戶端緩沖區溢出。預設配置為 client-output-buffer-limit slave 256MB 64MB 60,如果60s内緩沖區消耗持續大于64MB或者直接超過256MB時,主節點将直接關閉複制用戶端連接配接,造成全量同步失敗。

  • 7) 從節點接收完主節點傳送來的全部資料後會清空自身舊資料,該步驟對應如下日志。
  • 8) 從節點清空資料後開始加載 RDB 檔案,對于加大的 RDB 檔案,這一步操作依然比較耗時,可以通過計算日志之間的時間差來判斷加載 RDB 的總耗時。
  • 9) 收到 SYNC 指令的主伺服器執行 BGSAVE 指令,在背景生成一個 RDB 檔案,并使用一個緩沖區記錄從現在開始執行的所有寫指令。
  • 10) 當主伺服器的 BGSAVE 指令執行完畢時,主伺服器會将 GBSAVE 指令生成的 RDB 檔案發送給從伺服器,從伺服器接收并載入這個 RDB 檔案,将自己的資料庫狀态更新至主伺服器執行 BGSAVE 指令時的資料庫狀态。
  • 11) 主伺服器将記錄在緩沖區裡邊的所有寫指令發送給從伺服器,從伺服器執行這些寫指令,将自己的資料庫狀态更新至主伺服器資料庫目前所處的狀态。

通過分析全量複制的所有流程,讀者會發現全量複制是一個非常耗時費力的操作。它時間開銷主要包括:

  • 主節點 bgsave 時間
  • RDB 檔案網絡傳輸時間
  • 從節點清空資料時間
  • 從節點加載 RDB 的時間
  • 可能的 AOF 重寫時間

全量同步過程中不僅會消耗大量時間,還會進行多次持久化相關操作和網絡資料傳輸,這期間會大量消耗主從節點所在伺服器的 CPU、記憶體和網絡資源。是以,除了第一次複制是采用全量同步無法避免,其他場景應該規避全量複制,采取部分同步功能。

部分同步

部分複制主要是 Redis 針對全量複制的過高開銷做出的一種優化措施,使用 psync {runId} {offset} 指令實作。當從節點正在複制主節點時,如果出現網絡閃斷或者指令丢失等異常情況時,從節點會向主節點要求補發丢失的指令資料,如果主節點的複制積壓緩沖區存在這部分資料則直接發送給從節點,這樣就保證了主從節點複制的一緻性。補發的這部分資料一般遠遠小于全量資料,是以開銷很小。

redis詳解_Redis 複制過程詳解
  • 1) 當主從節點之間網絡出現中斷時,如果超過了 repl-timeout 時間,主節點會認為從節點故障并中斷複制連接配接。
  • 2) 主從連接配接中斷期間主節點依然響應指令,但因複制連接配接中斷指令無法發送給從節點,不過主節點内部存在複制積壓緩沖區( repl-backlog-buffer ),依然可以儲存最近一段時間的寫指令資料,預設最大緩存 1MB。
  • 3) 當主從節點網絡恢複後,從節點會再次連上主節點。
  • 4) 當主從連接配接恢複後,由于從節點之前儲存了自身已複制的偏移量和主節點的運作ID。是以會把它們作為 psync 參數發送給主節點,要求進行補發複制操作。
  • 5) 主節點接到 psync 指令後首先核對參數 runId 是否與自身一緻,如果一緻,說明之前複制的是目前主節點;之後根據參數 offset 在自身複制積壓緩沖區查找,如果偏移量之後的資料存在緩沖區中,則對從節點發送 +CONTINUE 響應,表示可以進行部分複制。
  • 6) 主節點根據偏移量把複制積壓緩沖區裡的資料發送給從節點,保證主從複制進入正常狀态。

心跳檢測

主從節點在建立複制後,它們之間維護着長連接配接并彼此發送心跳指令,如下圖所示。

主從心跳判斷機制如下所示:

  • 1) 主從節點彼此都有心跳檢測機制,各自模拟成對方的用戶端進行通信,通過 client list 指令檢視複制相關用戶端資訊,主節點的連接配接狀态為 flags=M,從節點連接配接狀态為 flags=S。
  • 2) 主節點預設每隔 10 秒對從節點發送 ping 指令,判斷從節點的存活性和連接配接狀态。可以通過參數 repl-ping-slave-period 控制發送頻率。
  • 3) 從節點在主線程中每隔 1 秒發送 replconf ack { offset } 指令,給主節點上報自己目前的複制偏移量。

replconf 指令不僅能實時監測主從節點網絡狀态,還能上報從節點複制偏移量。主節點會根據從節點上傳的偏移量檢查複制資料是否丢失,如果從節點資料丢失,再從主節點的複制緩存區中拉取丢失的資料發送給該從節點。

異步複制和指令傳播

主節點不但負責資料讀寫,還負責把寫指令同步給從節點。寫指令的發送過程是異步完成,也就是說主節點自身處理完寫指令後直接傳回給用戶端,并不等待從節點複制完成。

redis詳解_Redis 複制過程詳解

這個異步過程由指令傳播來處理,它不僅會将寫指令發送給所有從伺服器,還會将寫指令入隊到複制積壓緩沖區裡邊。

Redis 複制過程詳解​remcarpediem.net

redis詳解_Redis 複制過程詳解
redis詳解_Redis 複制過程詳解