1.複製過程
- 從節點執行 slaveof 命令。
- 從節點只是保存了 slaveof 命令中主節點的信息,並無當即發起複製。
- 從節點內部的定時任務發現有主節點的信息,開始使用 socket 鏈接主節點。
- 鏈接創建成功後,發送 ping 命令,但願獲得 pong 命令響應,不然會進行重連。
- 若是主節點設置了權限,那麼就須要進行權限驗證,若是驗證失敗,複製終止。
- 權限驗證經過後,進行數據同步,這是耗時最長的操做,主節點將把全部的數據所有發送給從節點。
- 當主節點把當前的數據同步給從節點後,便完成了複製的創建流程。接下來,主節點就會持續的把寫命令發送給從節點,保證主從數據一致性。
![](http://static.javashuo.com/static/loading.gif)
2.數據間的同步
上面說的複製過程,其中有一個步驟是「同步數據集」,這個就是如今講的「數據間的同步」。redis
redis 同步有 2 個命令:sync 和 psync,前者是 redis 2.8 以前的同步命令,後者是 redis 2.8 爲了優化 sync 新設計的命令。咱們會重點關注 2.8 的 psync 命令。緩存
psync 命令須要 3 個組件支持:
- 主從節點各自複製偏移量
- 主節點複製積壓緩衝區
- 主節點運行 ID
主從節點各自複製偏移量:
- 參與複製的主從節點都會維護自身的複製偏移量。
- 主節點在處理完寫入命令後,會把命令的字節長度作累加記錄,統計信息在 info replication 中的 masterreploffset 指標中。
- 從節點每秒鐘上報自身的的複製偏移量給主節點,所以主節點也會保存從節點的複製偏移量。
- 從節點在接收到主節點發送的命令後,也會累加自身的偏移量,統計信息在 info replication 中。
- 經過對比主從節點的複製偏移量,能夠判斷主從節點數據是否一致。
主節點複製積壓緩衝區:
- 複製積壓緩衝區是一個保存在主節點的一個固定長度的先進先出的隊列,默認大小 1MB。
- 這個隊列在 slave 鏈接是建立。這時主節點響應寫命令時,不但會把命令發送給從節點,也會寫入複製緩衝區。
- 他的做用就是用於部分複製和複製命令丟失的數據補救。經過 info replication 能夠看到相關信息。
主節點運行 ID:
- 每一個 redis 啓動的時候,都會生成一個 40 位的運行 ID。
- 運行 ID 的主要做用是用來識別 Redis 節點。若是使用 ip+port 的方式,那麼若是主節點重啓修改了 RDB/AOF 數據,從節點再基於偏移量進行復制將是不安全的。因此,當運行 id 變化後,從節點將進行全量複製。也就是說,redis 重啓後,默認從節點會進行全量複製。
若是在重啓時不改變運行 ID 呢?
- 能夠經過 debug reload 命令從新加載 RDB 並保持運行 ID 不變,從而有效的避免沒必要要的全量複製。
- 缺點是:debug reload 命令會阻塞當前 Redis 節點主線程,所以對於大數據量的主節點或者沒法容忍阻塞的節點,須要謹慎使用。通常經過故障轉移機制能夠解決這個問題。
psync 命令的使用方式:
命令格式爲 psync{runId}{offset}
安全
runId:從節點所複製主節點的運行 id 網絡
offset:當前從節點已複製的數據偏移量異步
psync 執行流程:
![](http://static.javashuo.com/static/loading.gif)
流程說明:socket
從節點發送 psync 命令給主節點,runId 就是目標主節點的 ID,若是沒有默認爲 -1,offset 是從節點保存的複製偏移量,若是是第一次複製則爲 -1.大數據
主節點會根據 runid 和 offset 決定返回結果:優化
- 若是回覆 +FULLRESYNC {runId} {offset} ,那麼從節點將觸發全量複製流程。
- 若是回覆 +CONTINUE,從節點將觸發部分複製。
- 若是回覆 +ERR,說明主節點不支持 2.8 的 psync 命令,將使用 sync 執行全量複製。
到這裏,數據之間的同步就講的差很少了,篇幅仍是比較長的。主要是針對 psync 命令相關之間的介紹。spa
3.全量複製
全量複製是 Redis 最先支持的複製方式,也是主從第一次創建複製時必須經歷的的階段。觸發全量複製的命令是 sync 和 psync。以前說過,這兩個命令的分水嶺版本是 2.8,redis 2.8 以前使用 sync 只能執行全量不一樣,2.8 以後同時支持全量同步和部分同步。線程
![](http://static.javashuo.com/static/loading.gif)
流程以下:
- 發送 psync 命令(spync ? -1)
- 主節點根據命令返回 FULLRESYNC
- 從節點記錄主節點 ID 和 offset
- 主節點 bgsave 並保存 RDB 到本地
- 主節點發送 RBD 文件到從節點
- 從節點收到 RDB 文件並加載到內存中
- 主節點在從節點接受數據的期間,將新數據保存到「複製客戶端緩衝區」,當從節點加載 RDB 完畢,再發送過去。(若是從節點花費時間過長,將致使緩衝區溢出,最後全量同步失敗)
- 從節點清空數據後加載 RDB 文件,若是 RDB 文件很大,這一步操做仍然耗時,若是此時客戶端訪問,將致使數據不一致,可使用配置slave-server-stale-data 關閉.
- 從節點成功加載完 RBD 後,若是開啓了 AOF,會馬上作 bgrewriteaof。
以上加粗的部分是整個全量同步耗時的地方。
注意:
- 如過 RDB 文件大於 6GB,而且是千兆網卡,Redis 的默認超時機制(60 秒),會致使全量複製失敗。能夠經過調大 repl-timeout 參數來解決此問題。
- Redis 雖然支持無盤複製,即直接經過網絡發送給從節點,但功能不是很完善,生產環境慎用。
4.部分複製
當從節點正在複製主節點時,若是出現網絡閃斷和其餘異常,從節點會讓主節點補發丟失的命令數據,主節點只須要將複製緩衝區的數據發送到從節點就可以保證數據的一致性,相比較全量複製,成本小不少。
![](http://static.javashuo.com/static/loading.gif)
- 當從節點出現網絡中斷,超過了 repl-timeout 時間,主節點就會中斷複製鏈接。
- 主節點會將請求的數據寫入到「複製積壓緩衝區」,默認 1MB。
- 當從節點恢復,從新鏈接上主節點,從節點會將 offset 和主節點 id 發送到主節點。
- 主節點校驗後,若是偏移量的數後的數據在緩衝區中,就發送 cuntinue 響應 —— 表示能夠進行部分複製。
- 主節點將緩衝區的數據發送到從節點,保證主從複製進行正常狀態。
5.心跳
主從節點在創建複製後,他們之間維護着長鏈接並彼此發送心跳命令。
心跳的關鍵機制以下:
- 中從都有心跳檢測機制,各自模擬成對方的客戶端進行通訊,經過 client list 命令查看複製相關客戶端信息,主節點的鏈接狀態爲 flags = M,從節點的鏈接狀態是 flags = S。
- 主節點默認每隔 10 秒對從節點發送 ping 命令,可修改配置 repl-ping-slave-period 控制發送頻率。
- 從節點在主線程每隔一秒發送 replconf ack{offset} 命令,給主節點上報自身當前的複製偏移量。
- 主節點收到 replconf 信息後,判斷從節點超時時間,若是超過 repl-timeout 60 秒,則判斷節點下線。
![](http://static.javashuo.com/static/loading.gif)
注意:
爲了下降主從延遲,通常把 redis 主從節點部署在相同的機房/同城機房,避免網絡延遲帶來的網絡分區形成的心跳中斷等狀況。
6.異步複製
主節點不但負責數據讀寫,還負責把寫命令同步給從節點,寫命令的發送過程是異步完成,也就是說主節點處理完寫命令後當即返回客戶度,並不等待從節點複製完成。
異步複製的步驟很簡單,以下:
- 主節點接受處理命令。
- 主節點處理完後返回響應結果 。
- 對於修改命令,異步發送給從節點,從節點在主線程中執行復制的命令。
![](http://static.javashuo.com/static/loading.gif)
總結
本文主要分析了 Redis 的複製原理,包括複製過程,數據之間的同步,全量複製的流程,部分複製的流程,心跳設計,異步複製流程。其中,能夠看出,RDB 數據之間的同步很是耗時。因此,Redis 在 2.8 版本退出了相似增量複製的 psync 命令,當 Redis 主從直接發生了網絡中斷,不會進行全量複製,而是將數據放到緩衝區(默認 1MB)裏,在經過主從之間各自維護複製 offset 來判斷緩存區的數據是否溢出,若是沒有溢出,只須要發送緩衝區數據便可,成本很小,反之,則要進行全量複製,所以,控制緩衝區大小很是的重要。