面試寶典系列-讀《深刻學習Redis(3):主從複製》概要

原文鏈接:深刻學習Redis(3):主從複製html

默認狀況下,每臺Redis服務器都是主節點;且一個主節點能夠有多個從節點(或沒有從節點),但一個從節點只能有一個主節點。redis

主從複製的做用主要包括:數據庫

  1. 數據冗餘:主從複製實現了數據的熱備份,是持久化以外的一種數據冗餘方式。
  2. 故障恢復:當主節點出現問題時,能夠由從節點提供服務,實現快速的故障恢復;其實是一種服務的冗餘。
  3. 負載均衡:在主從複製的基礎上,配合讀寫分離,能夠由主節點提供寫服務,由從節點提供讀服務(即寫Redis數據時應用鏈接主節點,讀Redis數據時應用鏈接從節點),分擔服務器負載;尤爲是在寫少讀多的場景下,經過多個從節點分擔讀負載,能夠大大提升Redis服務器的併發量。
  4. 高可用基石:除了上述做用之外,主從複製仍是哨兵和集羣可以實施的基礎,所以說主從複製是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種狀況:

  • 返回pong:說明socket鏈接正常,且主節點當前能夠處理請求,複製過程繼續。
  • 超時:必定時間後從節點仍未收到主節點的回覆,說明socket鏈接不可用,則從節點斷開socket鏈接,並重連。
  • 返回pong之外的結果:若是主節點返回其餘結果,如正在處理超時運行的腳本,說明主節點當前沒法處理命令,則從節點斷開socket鏈接,並重連。

步驟4:身份驗證

若是從節點中設置了masterauth選項,則從節點須要向主節點進行身份驗證;沒有設置該選項,則不須要驗證。從節點進行身份驗證是經過向主節點發送auth命令進行的,auth命令的參數即爲配置文件中的masterauth的值。

若是主節點設置密碼的狀態,與從節點masterauth的狀態一致(一致是指都存在,且密碼相同,或者都不存在),則身份驗證經過,複製過程繼續;若是不一致,則從節點斷開socket鏈接,並重連。

步驟5:發送從節點端口信息

身份驗證以後,從節點會向主節點發送其監聽的端口號(前述例子中爲6380),主節點將該信息保存到該從節點對應的客戶端的slave_listening_port字段中;該端口信息除了在主節點中執行info Replication時顯示之外,沒有其餘做用。

二、數據同步階段

主從節點之間的鏈接創建之後,即可以開始進行數據同步,該階段能夠理解爲從節點數據的初始化。具體執行的方式是:從節點向主節點發送psync命令(Redis2.8之前是sync命令),開始同步。

數據同步階段是主從複製最核心的階段,根據主從節點當前狀態的不一樣,能夠分爲全量複製和部分複製。

須要注意的是,在數據同步階段以前,從節點是主節點的客戶端,主節點不是從節點的客戶端;而到了這一階段及之後,主從節點互爲客戶端。緣由在於:在此以前,主節點只須要響應從節點的請求便可,不須要主動發請求,而在數據同步階段和後面的命令傳播階段,主節點須要主動向從節點發送請求(如推送緩衝區中的寫命令),才能完成複製。

3. 命令傳播階段

數據同步階段完成後,主從節點進入命令傳播階段;在這個階段主節點將本身執行的寫命令發送給從節點,從節點接收命令並執行,從而保證主從節點數據的一致性。

在命令傳播階段,除了發送寫命令,主從節點還維持着心跳機制:PING和REPLCONF ACK。

須要注意的是,命令傳播是異步的過程,即主節點發送寫命令後並不會等待從節點的回覆;所以實際上主從節點之間很難保持實時的一致性,延遲在所不免。

【數據同步階段】全量複製和部分複製

  1. 全量複製:用於初次複製或其餘沒法進行部分複製的狀況,將主節點中的全部數據都發送給從節點,是一個很是重型的操做。
  2. 部分複製:用於網絡中斷等狀況後的複製,只將中斷期間主節點執行的寫命令發送給從節點,與全量複製相比更加高效。須要注意的是,若是網絡中斷時間過長,致使主節點沒有可以完整地保存中斷期間執行的寫命令,則沒法進行部分複製,仍使用全量複製。

全量複製的過程

  1. 從節點判斷沒法進行部分複製,向主節點發送全量複製的請求;或從節點發送部分複製的請求,但主節點判斷沒法進行全量複製;具體判斷過程須要在講述了部分複製原理後再介紹。
  2. 主節點收到全量複製的命令後,執行bgsave,在後臺生成RDB文件,並使用一個緩衝區(稱爲複製緩衝區)記錄從如今開始執行的全部寫命令
  3. 主節點的bgsave執行完成後,將RDB文件發送給從節點;從節點首先清除本身的舊數據,而後載入接收的RDB文件,將數據庫狀態更新至主節點執行bgsave時的數據庫狀態
  4. 主節點將前述複製緩衝區中的全部寫命令發送給從節點,從節點執行這些寫命令,將數據庫狀態更新至主節點的最新狀態
  5. 若是從節點開啓了AOF,則會觸發bgrewriteaof的執行,從而保證AOF文件更新至主節點的最新狀態

經過全量複製的過程能夠看出,全量複製是很是重型的操做:

  • 主節點經過bgsave命令fork子進程進行RDB持久化,該過程是很是消耗CPU、內存(頁表複製)、硬盤IO的;
  • 主節點經過網絡將RDB文件發送給從節點,對主從節點的帶寬都會帶來很大的消耗
  • 從節點清空老數據、載入新RDB文件的過程是阻塞的,沒法響應客戶端的命令;若是從節點執行bgrewriteaof,也會帶來額外的消耗

部分複製,三個概念:

(1)複製偏移量

主節點和從節點分別維護一個複製偏移量(offset),表明的是主節點向從節點傳遞的字節數;主節點每次向從節點傳播N個字節數據時,主節點的offset增長N;從節點每次收到主節點傳來的N個字節數據時,從節點的offset增長N。

offset用於判斷主從節點的數據庫狀態是否一致:若是兩者offset相同,則一致;若是offset不一樣,則不一致,此時能夠根據兩個offset找出從節點缺乏的那部分數據。例如,若是主節點的offset是1000,而從節點的offset是500,那麼部分複製就須要將offset爲501-1000的數據傳遞給從節點。而offset爲501-1000的數據存儲的位置,就是下面要介紹的複製積壓緩衝區。

(2)複製積壓緩衝區

複製積壓緩衝區是由主節點維護的、固定長度的、先進先出(FIFO)隊列,默認大小1MB;當主節點開始有從節點時建立,其做用是備份主節點最近發送給從節點的數據。注意,不管主節點有一個仍是多個從節點,都只須要一個複製積壓緩衝區。

在命令傳播階段,主節點除了將寫命令發送給從節點,還會發送一份給複製積壓緩衝區,做爲寫命令的備份;除了存儲寫命令,複製積壓緩衝區中還存儲了其中的每一個字節對應的複製偏移量(offset)。因爲複製積壓緩衝區定長且是先進先出,因此它保存的是主節點最近執行的寫命令;時間較早的寫命令會被擠出緩衝區。

因爲該緩衝區長度固定且有限,所以能夠備份的寫命令也有限,當主從節點offset的差距過大超過緩衝區長度時,將沒法執行部分複製,只能執行全量複製。反過來講,爲了提升網絡中斷時部分複製執行的機率,能夠根據須要增大複製積壓緩衝區的大小(經過配置repl-backlog-size);例如若是網絡中斷的平均時間是60s,而主節點平均每秒產生的寫命令(特定協議格式)所佔的字節數爲100KB,則複製積壓緩衝區的平均需求爲6MB,保險起見,能夠設置爲12MB,來保證絕大多數斷線狀況均可以使用部分複製。

從節點將offset發送給主節點後,主節點根據offset和緩衝區大小決定可否執行部分複製:

  • 若是offset偏移量以後的數據,仍然都在複製積壓緩衝區裏,則執行部分複製;
  • 若是offset偏移量以後的數據已不在複製積壓緩衝區中(數據已被擠出),則執行全量複製。

(3)服務器運行ID(runid)

每一個Redis節點(不管主從),在啓動時都會自動生成一個隨機ID(每次啓動都不同),由40個隨機的十六進制字符組成;runid用來惟一識別一個Redis節點。經過info Server命令,能夠查看節點的runid:

主從節點初次複製時,主節點將本身的runid發送給從節點,從節點將這個runid保存起來;當斷線重連時,從節點會將這個runid發送給主節點;主節點根據runid判斷可否進行部分複製:

  • 若是從節點保存的runid與主節點如今的runid相同,說明主從節點以前同步過,主節點會繼續嘗試使用部分複製(到底能不能部分複製還要看offset和複製積壓緩衝區的狀況);
  • 若是從節點保存的runid與主節點如今的runid不一樣,說明從節點在斷線前同步的Redis節點並非當前的主節點,只能進行全量複製。

redis讀寫分離,能夠實現redis的讀負載均衡。

主從複製延遲與不一致問題的優化措施:優化主從節點之間的網絡環境(如在同機房部署);監控主從節點延遲(經過offset)判斷,若是從節點延遲過大,通知應用再也不經過該從節點讀取數據;使用集羣同時擴展寫負載和讀負載等。

複製中斷問題

主從節點超時是複製中斷的緣由之一,除此以外,還有其餘狀況可能致使複製中斷,其中最主要的是複製緩衝區溢出問題。

複製緩衝區溢出

前面曾提到過,在全量複製階段,主節點會將執行的寫命令放到複製緩衝區中,該緩衝區存放的數據包括瞭如下幾個時間段內主節點執行的寫命令:bgsave生成RDB文件、RDB文件由主節點發往從節點、從節點清空老數據並載入RDB文件中的數據。當主節點數據量較大,或者主從節點之間網絡延遲較大時,可能致使該緩衝區的大小超過了限制,此時主節點會斷開與從節點之間的鏈接;這種狀況可能引發全量複製->複製緩衝區溢出致使鏈接中斷->重連->全量複製->複製緩衝區溢出致使鏈接中斷……的循環。解決辦法:增大複製緩衝區

相關文章
相關標籤/搜索