原文鏈接:深刻學習Redis(3):主從複製html
默認狀況下,每臺Redis服務器都是主節點;且一個主節點能夠有多個從節點(或沒有從節點),但一個從節點只能有一個主節點。redis
主從複製的做用主要包括:數據庫
主從複製的開啓,徹底是在從節點發起的;不須要咱們在主節點作任何事情。服務器
主從複製過程大致能夠分爲3個階段:鏈接創建階段(即準備階段)、數據同步階段、命令傳播階段;網絡
步驟1:保存主節點信息:masterhost和masterport。slaveof是異步命令,從節點完成主節點ip和port的保存後,向發送slaveof命令的客戶端直接返回OK,實際的複製操做在這以後纔開始進行。併發
步驟2:創建socket鏈接:負載均衡
從節點每秒1次調用複製定時函數replicationCron(),若是發現了有主節點能夠鏈接,便會根據主節點的ip和port,建立socket鏈接。若是鏈接成功,則:異步
從節點:爲該socket創建一個專門處理複製工做的文件事件處理器,負責後續的複製工做,如接收RDB文件、接收命令傳播等。socket
主節點:接收到從節點的socket鏈接後(即accept以後),爲該socket建立相應的客戶端狀態,並將從節點看作是鏈接到主節點的一個客戶端,後面的步驟會以從節點向主節點發送命令請求的形式來進行。函數
步驟3:發送ping命令
從節點成爲主節點的客戶端以後,發送ping命令進行首次請求,目的是:檢查socket鏈接是否可用,以及主節點當前是否可以處理請求。
從節點發送ping命令後,可能出現3種狀況:
步驟4:身份驗證
若是從節點中設置了masterauth選項,則從節點須要向主節點進行身份驗證;沒有設置該選項,則不須要驗證。從節點進行身份驗證是經過向主節點發送auth命令進行的,auth命令的參數即爲配置文件中的masterauth的值。
若是主節點設置密碼的狀態,與從節點masterauth的狀態一致(一致是指都存在,且密碼相同,或者都不存在),則身份驗證經過,複製過程繼續;若是不一致,則從節點斷開socket鏈接,並重連。
步驟5:發送從節點端口信息
身份驗證以後,從節點會向主節點發送其監聽的端口號(前述例子中爲6380),主節點將該信息保存到該從節點對應的客戶端的slave_listening_port字段中;該端口信息除了在主節點中執行info Replication時顯示之外,沒有其餘做用。
主從節點之間的鏈接創建之後,即可以開始進行數據同步,該階段能夠理解爲從節點數據的初始化。具體執行的方式是:從節點向主節點發送psync命令(Redis2.8之前是sync命令),開始同步。
數據同步階段是主從複製最核心的階段,根據主從節點當前狀態的不一樣,能夠分爲全量複製和部分複製。
須要注意的是,在數據同步階段以前,從節點是主節點的客戶端,主節點不是從節點的客戶端;而到了這一階段及之後,主從節點互爲客戶端。緣由在於:在此以前,主節點只須要響應從節點的請求便可,不須要主動發請求,而在數據同步階段和後面的命令傳播階段,主節點須要主動向從節點發送請求(如推送緩衝區中的寫命令),才能完成複製。
數據同步階段完成後,主從節點進入命令傳播階段;在這個階段主節點將本身執行的寫命令發送給從節點,從節點接收命令並執行,從而保證主從節點數據的一致性。
在命令傳播階段,除了發送寫命令,主從節點還維持着心跳機制:PING和REPLCONF ACK。
須要注意的是,命令傳播是異步的過程,即主節點發送寫命令後並不會等待從節點的回覆;所以實際上主從節點之間很難保持實時的一致性,延遲在所不免。
全量複製的過程
經過全量複製的過程能夠看出,全量複製是很是重型的操做:
部分複製,三個概念:
主節點和從節點分別維護一個複製偏移量(offset),表明的是主節點向從節點傳遞的字節數;主節點每次向從節點傳播N個字節數據時,主節點的offset增長N;從節點每次收到主節點傳來的N個字節數據時,從節點的offset增長N。
offset用於判斷主從節點的數據庫狀態是否一致:若是兩者offset相同,則一致;若是offset不一樣,則不一致,此時能夠根據兩個offset找出從節點缺乏的那部分數據。例如,若是主節點的offset是1000,而從節點的offset是500,那麼部分複製就須要將offset爲501-1000的數據傳遞給從節點。而offset爲501-1000的數據存儲的位置,就是下面要介紹的複製積壓緩衝區。
複製積壓緩衝區是由主節點維護的、固定長度的、先進先出(FIFO)隊列,默認大小1MB;當主節點開始有從節點時建立,其做用是備份主節點最近發送給從節點的數據。注意,不管主節點有一個仍是多個從節點,都只須要一個複製積壓緩衝區。
在命令傳播階段,主節點除了將寫命令發送給從節點,還會發送一份給複製積壓緩衝區,做爲寫命令的備份;除了存儲寫命令,複製積壓緩衝區中還存儲了其中的每一個字節對應的複製偏移量(offset)。因爲複製積壓緩衝區定長且是先進先出,因此它保存的是主節點最近執行的寫命令;時間較早的寫命令會被擠出緩衝區。
因爲該緩衝區長度固定且有限,所以能夠備份的寫命令也有限,當主從節點offset的差距過大超過緩衝區長度時,將沒法執行部分複製,只能執行全量複製。反過來講,爲了提升網絡中斷時部分複製執行的機率,能夠根據須要增大複製積壓緩衝區的大小(經過配置repl-backlog-size);例如若是網絡中斷的平均時間是60s,而主節點平均每秒產生的寫命令(特定協議格式)所佔的字節數爲100KB,則複製積壓緩衝區的平均需求爲6MB,保險起見,能夠設置爲12MB,來保證絕大多數斷線狀況均可以使用部分複製。
從節點將offset發送給主節點後,主節點根據offset和緩衝區大小決定可否執行部分複製:
每一個Redis節點(不管主從),在啓動時都會自動生成一個隨機ID(每次啓動都不同),由40個隨機的十六進制字符組成;runid用來惟一識別一個Redis節點。經過info Server命令,能夠查看節點的runid:
主從節點初次複製時,主節點將本身的runid發送給從節點,從節點將這個runid保存起來;當斷線重連時,從節點會將這個runid發送給主節點;主節點根據runid判斷可否進行部分複製:
redis讀寫分離,能夠實現redis的讀負載均衡。
主從複製延遲與不一致問題的優化措施:優化主從節點之間的網絡環境(如在同機房部署);監控主從節點延遲(經過offset)判斷,若是從節點延遲過大,通知應用再也不經過該從節點讀取數據;使用集羣同時擴展寫負載和讀負載等。
主從節點超時是複製中斷的緣由之一,除此以外,還有其餘狀況可能致使複製中斷,其中最主要的是複製緩衝區溢出問題。
前面曾提到過,在全量複製階段,主節點會將執行的寫命令放到複製緩衝區中,該緩衝區存放的數據包括瞭如下幾個時間段內主節點執行的寫命令:bgsave生成RDB文件、RDB文件由主節點發往從節點、從節點清空老數據並載入RDB文件中的數據。當主節點數據量較大,或者主從節點之間網絡延遲較大時,可能致使該緩衝區的大小超過了限制,此時主節點會斷開與從節點之間的鏈接;這種狀況可能引發全量複製->複製緩衝區溢出致使鏈接中斷->重連->全量複製->複製緩衝區溢出致使鏈接中斷……的循環。解決辦法:增大複製緩衝區