天天看點

Redis主從複制原理及過期key處理(下)4 增量複制5 M關閉持久化時的複制安全性6 複制工作原理7 複制的完整流程8 斷點續傳9 無磁盤化複制10 處理過期key11 重新啟動和故障轉移後的部分重同步

4 增量複制

  1. 如果全量複制過程中,M-R網絡連接配接中斷,那麼salve重連M時,會觸發增量複制
  2. M直接從自己的backlog中擷取部分丢失的資料,發送給R node
  3. msater就是根據R發送的psync中的offset來從backlog中擷取資料的
Redis主從複制原理及過期key處理(下)4 增量複制5 M關閉持久化時的複制安全性6 複制工作原理7 複制的完整流程8 斷點續傳9 無磁盤化複制10 處理過期key11 重新啟動和故障轉移後的部分重同步

5 M關閉持久化時的複制安全性

在使用 Redis 複制功能時的設定中,推薦在 M 和 R 中啟用持久化。

當不可能啟用時,例如由于非常慢的磁盤性能而導緻的延遲問題,應該配置執行個體來避免重新開機後自動重新開始複制。

關閉持久化并配置了自動重新開機的 M 是危險的:

  1. 設定節點 A 為 M 并關閉它的持久化設定,節點 B 和 C 從 節點 A 複制資料
  2. 節點 A 當機,但它有一些自動重新開機系統可重新開機程序。但由于持久化被關閉了,節點重新開機後其資料集是空的!
  3. 這時B、C 會從A複制資料,但A資料集空,是以複制結果是它們會銷毀自身之前的資料副本!

當 Redis Sentinel 被用于高可用并且 M 關閉持久化,這時如果允許自動重新開機程序也是很危險的。例如, M 可以重新開機的足夠快以緻于 Sentinel 沒有探測到故障,是以上述的故障模式也會發生。

任何時候資料安全性都是很重要的,是以如果 M 使用複制功能的同時未配置持久化,那麼自動重新開機程序這項就該被禁用。

用Redis主從同步,寫入Redis的資料量太大,沒加頻次控制,導緻每秒幾十萬寫入,主從延遲過大,運維頻頻報警,在主庫不挂掉的情況下,這樣大量寫入會不會造成資料丢失?

若主從延遲很大,資料會堆積到redis主庫的發送緩沖區,會導緻主庫OOM。

6 複制工作原理

每個 M 都有一個 replication ID :一個較大的僞随機字元串,标記了一個給定的資料集。

Redis主從複制原理及過期key處理(下)4 增量複制5 M關閉持久化時的複制安全性6 複制工作原理7 複制的完整流程8 斷點續傳9 無磁盤化複制10 處理過期key11 重新啟動和故障轉移後的部分重同步

每個 M 也持有一個偏移量,M 将自己産生的複制流發送給 R 時,發送多少個位元組的資料,自身的偏移量就會增加多少,目的是當有新的操作修改自己的資料集時,它可據此更新 R 的狀态。

Redis主從複制原理及過期key處理(下)4 增量複制5 M關閉持久化時的複制安全性6 複制工作原理7 複制的完整流程8 斷點續傳9 無磁盤化複制10 處理過期key11 重新啟動和故障轉移後的部分重同步

複制偏移量即使在沒有一個 R 連接配接到 M 時,也會自增,是以基本上每一對給定的

Replication ID, offset

都會辨別一個 M 資料集的确切版本。

psync

R使用

psync

從M複制,psync runid offset

Redis主從複制原理及過期key處理(下)4 增量複制5 M關閉持久化時的複制安全性6 複制工作原理7 複制的完整流程8 斷點續傳9 無磁盤化複制10 處理過期key11 重新啟動和故障轉移後的部分重同步

M會根據自身情況傳回響應資訊:

  • 可能是FULLRESYNC runid offset觸發全量複制
  • 可能是CONTINUE觸發增量複制

R 連接配接到 M 時,它們使用 PSYNC 指令來發送它們記錄的舊的 M replication ID 和它們至今為止處理的偏移量。通過這種方式, M 能夠僅發送 R 所需的增量部分。

但若 M 的緩沖區中沒有足夠的指令積壓緩沖記錄,或者如果 R 引用了不再知道的曆史記錄(replication ID),則會轉而進行一個全量重同步:在這種情況下, R 會得到一個完整的資料集副本,從頭開始。即:

  • 若R重連M,那麼M僅會複制給R缺少的部分資料
  • 若第一次連接配接M,那麼會觸發全量複制

Redis使用複制保證資料同步,以2.8版本為界:

2.8前性能較差的複制和指令傳播

首先是從伺服器發生同步操作sync,主伺服器執行bgsave生成一個全量RDB檔案,然後傳輸給從伺服器。

同時主伺服器會把這一過程中執行的寫指令寫入緩存區。從伺服器會把RDB檔案進行一次全量加載。

加載完畢後,主伺服器會把緩存區中的寫指令傳給從伺服器。從伺服器執行指令後,主從伺服器的資料就一緻了。

這種方式每次如果網絡出現故障,故障重連後都要進行全量資料的複制。對主伺服器的壓力太大,也會增加主從網絡傳輸的資源消耗。

2.8後的優化

增加部分重同步功能,就是同步故障後的一部分資料,而非全量資料。這種優化在量級非常大的情況下效率提升很明顯。

4.0的PSYNC2

7 複制的完整流程

Redis主從複制原理及過期key處理(下)4 增量複制5 M關閉持久化時的複制安全性6 複制工作原理7 複制的完整流程8 斷點續傳9 無磁盤化複制10 處理過期key11 重新啟動和故障轉移後的部分重同步

R如果跟M有網絡故障,斷開連接配接會自動重連。

M如果發現有多個R都重新連接配接,僅會啟動一個rdb save操作,用一份資料服務所有R。

  1. R啟動,僅儲存M的資訊,包括M的

    host

    ip

    ,但複制流程尚未開始M host和ip配置在

    redis.conf

    中的 Rof
  2. R内部有個定時任務,每s檢查是否有新的M要連接配接和複制,若發現,就跟M建立socket網絡連接配接。
  3. R發送ping指令給M
  4. 密碼認證 - 若M設定了requirepass,那麼salve必須同時發送Mauth的密碼認證
  5. M 第一次執行全量複制,将所有資料發給R
  6. M後續持續将寫指令,異步複制給R

heartbeat

主從節點互相都會發送heartbeat資訊。

M預設每隔10秒發送一次heartbeat,salve node每隔1秒發送一個heartbeat。

8 斷點續傳

Redis 2.8開始支援主從複制的斷點續傳

Redis主從複制原理及過期key處理(下)4 增量複制5 M關閉持久化時的複制安全性6 複制工作原理7 複制的完整流程8 斷點續傳9 無磁盤化複制10 處理過期key11 重新啟動和故障轉移後的部分重同步

主從複制過程,若網絡連接配接中斷,那麼可以接着上次複制的地方,繼續複制下去,而不是從頭開始複制一份。

M和R都會維護一個offset

  • M在自身基礎上累加offset,R亦是
  • R每秒都會上報自己的offset給M,同時M儲存每個R的offset

M和R都要知道各自資料的offset,才能知曉互相之間的資料不一緻情況。

backlog

M會在記憶體中維護一個backlog,預設1MB。M給R複制資料時,也會将資料在backlog中同步寫一份。

backlog主要是用做全量複制中斷時候的增量複制。

M和R都會儲存一個replica offset還有一個M id,offset就是儲存在backlog中的。若M和R網絡連接配接中斷,R會讓M從上次replica offset開始繼續複制。但若沒有找到對應offset,就會執行resynchronization。

M run id

  • info server,可見M run id
Redis主從複制原理及過期key處理(下)4 增量複制5 M關閉持久化時的複制安全性6 複制工作原理7 複制的完整流程8 斷點續傳9 無磁盤化複制10 處理過期key11 重新啟動和故障轉移後的部分重同步

根據host+ip定位M node,是不靠譜的,如果M node重新開機或者資料出現了變化,那麼R node應該根據不同的run id區分,run id不同就做全量複制。

如果需要不更改run id重新開機redis,可使用:

redis-cli debug reload      

9 無磁盤化複制

M在記憶體中直接建立RDB,然後發送給R,不會在自己本地持久化。

隻需要在配置檔案中開啟

repl-diskless-sync yes

即可.

等待 5s 再開始複制,因為要等更多 R 重連
repl-diskless-sync-delay 5
      

10 處理過期key

Redis 的過期機制可以限制 key 的生存時間。此功能取決于 Redis 執行個體計算時間的能力,但是,即使使用 Lua 腳本更改了這些 key,Redis Rs 也能正确地複制具有過期時間的 key。

為實作功能,Redis 不能依靠主從使用同步時鐘,因為這是一個無法解決的問題并且會導緻 race condition 和資料不一緻,是以 Redis 使用三種主要的技術使過期的 key 的複制能夠正确工作:

R 不會讓 key 過期,而是等待 M 讓 key 過期。當一個 M 讓一個 key 到期(或由于 LRU 删除)時,它會合成一個 DEL 指令并傳輸到所有 R

但由于這是 M 驅動的 key 過期行為,M 無法及時提供 DEL 指令,是以有時 R 的記憶體中仍可能存在邏輯上已過期的 key 。為處理該問題,R 使用它的邏輯時鐘以報告隻有在不違反資料集的一緻性的讀取操作(從主機的新指令到達)中才存在 key。用這種方法,R 避免報告邏輯過期的 key 仍然存在。在實際應用中,使用 R 程式進行縮放的 HTML 碎片緩存,将避免傳回已經比期望的時間更早的資料項

在Lua腳本執行期間,不執行任何 key 過期操作

當一個Lua腳本運作時,概念上講,M 中的時間是被當機的,這樣腳本運作的時候,一個給定的鍵要麼存在or不存在。這可以防止 key 在腳本中間過期,保證将相同的腳本發送到 R ,進而在二者的資料集中産生相同的效果。

一旦 R 被提升 M ,它将開始獨立過期 key,而不需要任何舊 M 幫助。

11 重新啟動和故障轉移後的部分重同步

Redis 4.0 開始,當一個執行個體在故障轉移後被提升為 M 時,它仍然能夠與舊 M 的 R 進行部分重同步。為此,R 會記住舊 M 的舊 replication ID 和複制偏移量,是以即使詢問舊的 replication ID,也可以将部分複制緩沖提供給連接配接的 R 。

但是,更新的 R 的新 replication ID 将不同,因為它構成了資料集的不同曆史記錄。例如,M 可以傳回可用,并且可以在一段時間内繼續接受寫入指令,是以在被提升的 R 中使用相同的 replication ID 将違反一對複制辨別和偏移對隻能辨別單一資料集的規則。

另外,R 在關機并重新啟動後,能夠在 RDB 檔案中存儲所需資訊,以便與 M 進行重同步。這在更新的情況下很有用。當需要時,最好使用 SHUTDOWN 指令來執行 R 的儲存和退出操作。

參考

繼續閱讀