深入詳解Redis 主從複製的原理!

若小寒發表於2019-03-24

一.複製過程

複製的過程步驟如下:

  1. 從節點執行 slaveof 命令
  2. 從節點只是儲存了 slaveof 命令中主節點的資訊,並沒有立即發起複製
  3. 從節點內部的定時任務發現有主節點的資訊,開始使用 socket 連線主節點
  4. 連線建立成功後,傳送 ping 命令,希望得到 pong 命令響應,否則會進行重連 
  5. 如果主節點設定了許可權,那麼就需要進行許可權驗證;如果驗證失敗,複製終止。
  6. 許可權驗證通過後,進行資料同步,這是耗時最長的操作,主節點將把所有的資料全部傳送給從節點。
  7. 當主節點把當前的資料同步給從節點後,便完成了複製的建立流程。接下來,主節點就會持續的把寫命令傳送給從節點,保證主從資料一致性

深入詳解Redis 主從複製的原理!

二.資料間的同步

上面說的複製過程,其中有一個步驟是“同步資料集”,這個就是現在講的‘資料間的同步’。

redis 同步有 2 個命令:

sync 和 psync,前者是 redis 2.8 之前的同步命令,後者是 redis 2.8 為了優化 sync 新設計的命令。我們會重點關注 2.8 的 psync 命令。

psync 命令需要 3 個元件支援:

  1. 主從節點各自複製偏移量 
  2. 主節點複製積壓緩衝區
  3. 主節點執行 ID

主從節點各自複製偏移量:

  1. 參與複製的主從節點都會維護自身的複製偏移量。
  2. 主節點在處理完寫入命令後,會把命令的位元組長度做累加記錄,統計資訊在 info replication 中的 masterreploffset 指標中。
  3. 從節點每秒鐘上報自身的的複製偏移量給主節點,因此主節點也會儲存從節點的複製偏移量。
  4. 從節點在接收到主節點傳送的命令後,也會累加自身的偏移量,統計資訊在 info replication 中。
  5. 通過對比主從節點的複製偏移量,可以判斷主從節點資料是否一致。

主節點複製積壓緩衝區:

  1. 複製積壓緩衝區是一個儲存在主節點的一個固定長度的先進先出的佇列。預設大小 1MB。
  2. 這個佇列在 slave 連線是建立。這時主節點響應寫命令時,不但會把命令傳送給從節點,也會寫入複製緩衝區。
  3. 他的作用就是用於部分複製和複製命令丟失的資料補救。通過 info replication 可以看到相關資訊。

主節點執行 ID:

  1. 每個 redis 啟動的時候,都會生成一個 40 位的執行 ID。
  2. 執行 ID 的主要作用是用來識別 Redis 節點。如果使用 ip+port 的方式,那麼如果主節點重啟修改了 RDB/AOF 資料,從節點再基於偏移量進行復制將是不安全的。所以,當執行 id 變化後,從節點將進行全量複製。也就是說,redis 重啟後,預設從節點會進行全量複製。

如果在重啟時不改變執行 ID 呢?

  1. 可以通過 debug reload 命令重新載入 RDB 並保持執行 ID 不變。從而有效的避免不必要的全量複製。
  2. 他的缺點則是:debug reload 命令會阻塞當前 Redis 節點主執行緒,因此對於大資料量的主節點或者無法容忍阻塞的節點,需要謹慎使用。一般通過故障轉移機制可以解決這個問題。

psync 命令的使用方式:

命令格式為 psync{runId}{offset}

runId:從節點所複製主節點的執行 id offset:當前從節點已複製的資料偏移量

psync 執行流程:

深入詳解Redis 主從複製的原理!

流程說明:從節點傳送 psync 命令給主節點,runId 就是目標主節點的 ID,如果沒有預設為 -1,offset 是從節點儲存的複製偏移量,如果是第一次複製則為 -1.

主節點會根據 runid 和 offset 決定返回結果:

  1. 如果回覆 +FULLRESYNC {runId} {offset} ,那麼從節點將觸發全量複製流程。
  2. 如果回覆 +CONTINUE,從節點將觸發部分複製。
  3. 如果回覆 +ERR,說明主節點不支援 2.8 的 psync 命令,將使用 sync 執行全量複製。

到這裡,資料之間的同步就講的差不多了,篇幅還是比較長的。主要是針對 psync 命令相關之間的介紹。

三.全量複製

全量複製是 Redis 最早支援的複製方式,也是主從第一次建立複製時必須經歷的的階段。觸發全量複製的命令是 sync 和 psync。之前說過,這兩個命令的分水嶺版本是 2.8,redis 2.8 之前使用 sync 只能執行全量不同,2.8 之後同時支援全量同步和部分同步。

流程如下:

深入詳解Redis 主從複製的原理!

介紹一下上圖步驟:

  1. 傳送 psync 命令(spync ? -1)
  2. 主節點根據命令返回 FULLRESYNC 
  3. 從節點記錄主節點 ID 和 offset 
  4. 主節點 bgsave 並儲存 RDB 到本地
  5. 主節點傳送 RBD 檔案到從節點
  6. 從節點收到 RDB 檔案並載入到記憶體中
  7. 主節點在從節點接受資料的期間,將新資料儲存到“複製客戶端緩衝區”,當從節點載入 RDB 完畢,再傳送過去。(如果從節點花費時間過長,將導致緩衝區溢位,最後全量同步失敗)
  8. 從節點清空資料後載入 RDB 檔案,如果 RDB 檔案很大,這一步操作仍然耗時,如果此時客戶端訪問,將導致資料不一致,可以使用配置slave-server-stale-data 關閉
  9. 從節點成功載入完 RBD 後,如果開啟了 AOF,會立刻做 bgrewriteaof

以上加粗的部分是整個全量同步耗時的地方。

注意:

  1. 如過 RDB 檔案大於 6GB,並且是千兆網路卡,Redis 的預設超時機制(60 秒),會導致全量複製失敗。可以通過調大 repl-timeout 引數來解決此問題
  2. Redis 雖然支援無盤複製,即直接通過網路傳送給從節點,但功能不是很完善,生產環境慎用。

四.部分複製

當從節點正在複製主節點時,如果出現網路閃斷和其他異常,從節點會讓主節點補發丟失的命令資料,主節點只需要將複製緩衝區的資料傳送到從節點就能夠保證資料的一致性,相比較全量複製,成本小很多。

步驟如下:

深入詳解Redis 主從複製的原理!

  1. 當從節點出現網路中斷,超過了 repl-timeout 時間,主節點就會中斷複製連線。
  2. 主節點會將請求的資料寫入到“複製積壓緩衝區”,預設 1MB。
  3. 當從節點恢復,重新連線上主節點,從節點會將 offset 和主節點 id 傳送到主節點
  4. 主節點校驗後,如果偏移量的數後的資料在緩衝區中,就傳送 cuntinue 響應 —— 表示可以進行部分複製 
  5. 主節點將緩衝區的資料傳送到從節點,保證主從複製進行正常狀態。

五.心跳

主從節點在建立複製後,他們之間維護著長連線並彼此傳送心跳命令。

心跳的關鍵機制如下:

  1. 中從都有心跳檢測機制,各自模擬成對方的客戶端進行通訊,通過 client list 命令檢視複製相關客戶端資訊,主節點的連線狀態為 flags = M,從節點的連線狀態是 flags = S。
  2. 主節點預設每隔 10 秒對從節點傳送 ping 命令,可修改配置 repl-ping-slave-period 控制傳送頻率。
  3. 從節點在主執行緒每隔一秒傳送 replconf ack{offset} 命令,給主節點上報自身當前的複製偏移量。
  4. 主節點收到 replconf 資訊後,判斷從節點超時時間,如果超過 repl-timeout 60 秒,則判斷節點下線。

深入詳解Redis 主從複製的原理!

注意:為了降低主從延遲,一般把 redis 主從節點部署在相同的機房/同城機房,避免網路延遲帶來的網路分割槽造成的心跳中斷等情況。

六.非同步複製

主節點不但負責資料讀寫,還負責把寫命令同步給從節點,寫命令的傳送過程是非同步完成,也就是說主節點處理完寫命令後立即返回客戶度,並不等待從節點複製完成。

非同步複製的步驟很簡單,如下:

  1. 主節點接受處理命令
  2. 主節點處理完後返回響應結果
  3. 對於修改命令,非同步傳送給從節點,從節點在主執行緒中執行復制的命令。

深入詳解Redis 主從複製的原理!

總結

本文主要分析了 Redis 的複製原理,包括複製過程,資料之間的同步,全量複製的流程,部分複製的流程,心跳設計,非同步複製流程。

其中,可以看出,RDB 資料之間的同步非常耗時。所以,Redis 在 2.8 版本退出了類似增量複製的 psync 命令,當 Redis 主從直接發生了網路中斷,不會進行全量複製,而是將資料放到緩衝區(預設 1MB)裡,在通過主從之間各自維護複製 offset 來判斷快取區的資料是否溢位,如果沒有溢位,只需要傳送緩衝區資料即可,成本很小,反之,則要進行全量複製,因此,控制緩衝區大小非常的重要。

最後

後續會持續更新Redis專題知識,寫的不好的地方也希望大牛能指點一下,大家覺得不錯可以點個贊在關注下,以後還會分享更多文章!

分享免費學習資料
歡迎工作一到五年的Java工程師朋友們加入QQ群Java架構交流:714827309,針對於Redis學習我已經錄製了錄播免費提供,還會提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)
為什麼某些人會一直比你優秀,是因為他本身就很優秀還一直在持續努力變得更優秀,而你是不是還在滿足於現狀內心在竊喜!
(部分資料如下)

深入詳解Redis 主從複製的原理!

深入詳解Redis 主從複製的原理!

相關文章