Redis 主從複製詳細解讀

單臺 redis 面臨的問題

在實際場景中,單一節點的 redis 容易面臨風險node

  • 機器故障git

    • 咱們部署到一臺 redis 服務器,當發生機器故障時,須要遷移到另外一臺服務器而且要保證數據是同步的,而數據是最重要的。單臺機器沒法保證數據的安全
  • 容量瓶勁github

    • 當咱們有需求須要擴容 redis 內存時,從16G 內存升級到 64G,單機確定是知足不了,除非從新買一個128G的機器
  • 總結redis

    • 要實現分佈式數據庫更大的存儲容量和承受高併發訪問量,咱們會將原來集中式數據庫的數據分別存儲到其餘多個網絡節點上
    • Redis 爲了解決這個單一節點的問題,也會把數據複製多個副本部署到其餘節點上進行復制,實現 Redis 的高可用,實現對數據的冗餘備份,從而保證數據和服務的高可用

什麼是主從複製

  • 主從複製,是指將一臺 Redis 服務器的數據,複製到其餘的 Redis 服務器,前者成爲 master 主節點,後者成爲 slave 從節點,數據的複製是單向的,只能由主節點到從節點。
  • 默認狀況下,每臺 redis 服務器都是主節點,且一個主節點能夠有多個從節點,但一個從節點只能有一個主節點

主從複製的做用

數據冗餘

  • 主從複製實現了數據的熱備份,是持久化以外的另外一種數據冗餘方式

故障恢復

  • 當主節點出現問題時,能夠由從節點提供服務,實現快速的故障恢復,其實是一種服務的冗餘

負載均衡

  • 在主從複製的基礎上,配合讀寫分離,能夠由主節點提供寫服務,由從節點提供讀服務。「即寫 Redis 數據時應用鏈接主節點,讀 Redis 數據時應用鏈接從節點」分擔服務器負載,尤爲是在 「寫少讀多」 的場景下,經過多個從節點分擔讀負載,能夠大大提升 Redis 服務器的併發量

讀寫分離

  • 能夠用於實現讀寫分離,主庫寫,從庫讀,讀寫分離不只能夠提升服務器的負載能力,同時可根據需求的變化,改變從庫的數量

高可用的基石

  • 除了上述的做用外,主從複製仍是哨兵和集羣可以實施的基礎,所以說主從複製是 Redis 高可用的基石

主從複製啓用

從節點開啓主從複製,有3中方式

  • 配置文件數據庫

    • 在從服務器的配置文件中加入: slaveof
  • 啓動命令安全

    • redis-server 啓動命令後加上 --slaveof
  • 客戶端命令服務器

    • Redis 服務器啓動後,直接經過客戶端執行命令 slaveof 則該Redis實例成爲從節點
查看複製信息

-   經過 info replication 命令能夠看到複製的一些信息

配置文件中注意事項

-   查看 LOG 文件位置
-   保護模式
-   密碼配置

主從複製原理

  • 主從複製大致分爲3個步驟:

    1.鏈接創建階段「準備階段」網絡

    2.數據同步階段架構

    3.命令傳播階段併發

  • 從節點執行 slaveof 命令後,會進行如下步驟進行復制

    • 主從配置信息以後的日誌記錄也能夠看出以上流程
    1. 保存主節點信息

      • 執行 slaveof 後,redis 會打印如下日誌信息\

    2. 主從節點創建 socket 鏈接

      • 從節點經過內部運行定時任務,維護複製相關邏輯,當定時任務發現新的主節點後,會嘗試與該節點進行網絡鏈接

        • 從節點與主節點創建網絡鏈接\

        • 從節點會創建一個 socket 套接字,而後創建一個端口爲 51234 的套接字,專門用戶接收主節點發送的複製命令,從節點創建鏈接後的日誌\

        • 若是從節點沒法創建鏈接,定時任務會無限重試直到鏈接成功或者執行 slaveof no one 取消複製
        • 關於鏈接失敗

          • 在從節點執行 info replication 命令查看 master_link_down_since_seconds 這個指標,它會記錄與主節點鏈接失敗的系統時間
          • 從節點鏈接主節點失敗時,也會在日誌中每秒打印失敗信息 # Error condition on socket for SYNC: {socket_error_reason}
    3. 發送Ping 命令

      • 創建鏈接成功後,從節點發送 Ping 請求進行首次通訊,Ping 命令的主要目的

        • 檢測主從之間網絡套接字是否可用
        • 檢測主節點當前是否能夠接收命令
      • 若是發送 Ping 命令以後,從節點沒有收到主節點的 Pong 回覆或者網絡超時,好比網絡超時或者主節點阻塞沒法響應命令,從節點會斷開復制鏈接,下次定時任務會發起重連
![](https://raw.githubusercontent.com/xiaoshuaizhou/pic/master/pic/輪訓重試.png)

    \

    ![](https://raw.githubusercontent.com/xiaoshuaizhou/pic/master/pic/發起重連.png)

    -   從節點發送的 Ping 命令成功返回後,Redis 打印日誌,並繼續後續的複製流程

    ![](https://raw.githubusercontent.com/xiaoshuaizhou/pic/master/pic/ping成功日誌.png)

4.  權限驗證

    -   若是主節點設置了 requirepass 參數,則須要密碼驗證,從節點必須配置 masterauth 參數保證與主節點相同的密碼才能驗證經過,若是驗證失敗,複製將終止,從節點從新發起復制流程
5.  同步數據集

    -   主從複製鏈接正常通訊後,對於首次創建的複製場景,主節點會把全部的數據所有發送給從節點,這步是耗時最長的步驟
6.  命令持續複製

    -   當主節點把當前數據所有發送到從節點後,便完成了複製流程,接下來主節點會持續的把命令發送給從節點,保證主從數據的一致性

    ![](https://raw.githubusercontent.com/xiaoshuaizhou/pic/master/pic/命令持續複製.png)

全量複製和部分複製

全量複製

  • 用於初次複製或者其餘沒法進行部分複製的狀況,將主節點的全部數據都發送給從節點,是一個很是重型的操做,當數據量較大時,會對主從節點和網絡形成很大的開銷
  • 全量複製過程

    1. redis-slave 內部會發出一個同步命令,剛開始是 Psync 命令 , Psync?-1 表示請求 master 主節點同步數據
    2. 主機向從節點發送 runid 和 offset ,由於從節點並無 對應 的 offset ,因此是全量複製
    3. 從節點會保存主機的相關信息 save masterinfo
    4. 主機接收到複製命令後,執行 bgsave「異步執行」在後臺生成 RDB 快照文件,並使用一個緩衝區「複製積壓緩衝區」來記錄如今開始執行的全部寫命令
    5. 主機 send RDB 發送 RDB 快照文件給從機
    6. 發送緩衝區數據
    7. 刷新舊的數據,從節點在接收主節點數據以前將以前原有的老數據清空
    8. 加載 RDB 快照文件,將數據庫狀態更新直主機執行 gbsave 時的數據庫狀態和緩衝區數據的加載
  • 全量複製的開銷

    • bgsave 的時間
    • RDB 文件網絡傳輸時間
    • 從節點清空數據的時間
    • 從節點加載 RDB 文件的時間

部分複製

  • 部分複製是 Redis 2.8 之後出現的,之因此要加上部分複製,是由於全量複製會出現不少的問題,好比開銷時間大,沒法隔離等問題。\
    redis 但願在網絡抖動的時候,能夠有一些機制將複製的損失降到最低;
  • 用於處理在主從複製中因網絡閃斷等緣由形成的數據丟失場景,當從節點再次連上主節點後,若是條件容許,主節點會補發丟失數據給從節點,由於補發的數據遠遠小於全量數據,能夠有效避免全量複製的太高開銷,須要注意的是,若是網絡中斷時間過長,形成主節點沒有可以完整的保存中斷期間執行的寫命令,則沒法進行部分複製,仍使用全量複製
  • 部分複製的過程

    1. 若是網絡抖動(connection lost)
    2. Redis 主機仍是會寫 replbackbuffer「複製積壓緩衝區」
    3. 從機 slave 會繼續鏈接從機
    4. 從機把本身當前的 runid 和 offset 發送給主機,而且執行 Pysnc 執行同步
    5. 若是 master 主機發現偏移量在複製積壓緩衝區的範圍內,就會返回 continue 命令,繼續執行同步
    6. 同步了 offset 的數據,因此部分複製是基於 offset 「偏移量」的

redis 是如何決定使用全量複製或部分複製的?

  • redis 選擇決策

    • 從節點將 offset 發送給主節點後,主節點根據偏移量和複製緩衝區大小來決定是否執行部分複製
    • 若是offset 偏移量以後的數據,仍然在複製積壓緩衝區的話,使用部分複製
    • 若是 offset 偏移量以後的數據,已經不在積壓緩衝區的話,說明數據已經被擠出,因此進行全量複製
  • 如何避免全量複製?

    1. 調整積壓緩衝區的大小

      • 因爲緩衝區大小固定且有限,所以能夠備份的數據也有限,當主從節點的 offset 差距過大超過積壓緩衝區時,沒法進行部分複製,只能使用全量複製;
      • 反過來講,爲了提升網絡中斷時部分複製的使用機率,能夠根據須要增大複製緩衝區的大小來調節「經過配置 repl_backlog_size」來設置。
      • 例如:若是網絡中斷的平均時間是 60S,而主節點平均每秒執行的寫命令是 100KB,則複製積壓緩衝區的平均需求爲 6MB, 爲了保險期間,設置成 12MB來保證絕大多數斷線狀況下可使用部分複製
    2. 服務器運行ID「runid」

      • 每一個redis 機器「不管主從」在啓動時都會隨機生成一個隨機的ID「每次啓動都不同」,由40個隨機的十六進制的字符組成;runid 用來惟一表示 redis 節點,經過 info server 命令查看 runid
      • 主節點初次複製時,主節點將本身的runid 發送給從節點,從節點把這個 runid 保存起來,當斷線重連時,從節點將這個 runid 發送給主節點,主節點用這個 runid 來判斷是否能夠進行部分複製
      • 若是從節點發送的runid 和 主節點的runid 相同,說明主從節點以前通不過,主節點會嘗試繼續使用部分複製「真正決定使用部分複製的仍是offset 和複製積壓緩衝區的大小」
      • 若是從節點發送「保存」的 runid 和如今主節點的 runid 不一樣,說明以前主從沒有同步過數據,只能進行全量複製

複製偏移量

  • 參與複製中的從節點都會維護自身複製偏移量。
  • 主節點

    • 主節點在處理完寫入命令後,會把命令的字節長度作累加記錄,統計信息在 info replication 中的 master_repl_offset 指標中
  • 從節點

    • 從節點每秒鐘上報自身的複製偏移量給主節點,所以主節點也會保存從節點的複製偏移量
    • 從節點在接收到主節點發送的命令後,也會累加記錄自身的偏移量。統計信息在 info replication 中的 slave_repl_offset 中

複製積壓緩衝區

  • 複製積壓緩衝區:是保存在主節點上的一個固定長度的隊列,默認大小是 1MB,當主節點有鏈接的從節點時被建立,這時主節點響應寫命令時,不但會把命令發送給從節點,還會寫入複製積壓緩衝區
  • 命令傳播階段,主節點除了將寫命令發送給從節點,還會發送一份給複製積壓緩衝區,做爲寫命令的備份;
  • 除了存儲寫命令,複製積壓緩衝區中還存儲了其中的每一個字節對應的複製偏移量「offset」。
  • 因爲複製積壓緩衝區定長,而且先進先出。因此它保存的是主節點最近執行的寫命令,時間較早的寫命令會被擠出緩衝區

主從複製的經常使用相關配置

從數據庫配置

  • 1. slaveof

    slave 節點須要配置該項,指向 master 的 IP 和 端口

  • 2.masterauth

    若是 master 啓用了密碼保護,則配置該項須要填寫 master 的啓動密碼,若是master 未啓動該項,則該項須要註釋

  • 3. slave-server-stale-data

    指定 master 和 slave 鏈接中斷時的動做。\
    默認是 yes,表示 slave 會繼續應答來自 client的請求,但這些數據可能已通過期「由於鏈接中斷可能沒法進行master同步」;

    若配置爲 no , 則 slave 除正常應答 INFO 和 slaveof 「配置命令」外,其他來自客戶端的請求命令均會獲得 「SYNC with master in progress」 的應答,直到該 slave 和master重建鏈接成功或者 slave 提高爲 master

  • 4. slave-read-only

    指定 slave 是否爲只讀,默認爲 yes\
    若配置爲 no ,表示slave 是可寫的,但寫的內容在主從同步之後會被清空

  • 5. repl-disable-tcp-nodaly

    指定向 slave 同步數據時,是否禁用 socket 的NO_DALY 選項,若配置爲 yes ,則表示禁用 NO_DALY ,則 tcp 協議棧會合並小包統一發送,這樣能夠減小主從傳輸間的包數量和減小帶寬,但會增長同步到 slave 的時間;

    若配置爲 no , 代表啓用 NO_DALY,則 tcp 協議棧 不會延遲小包的發送時機,這樣數據同步的延時會減小,但須要更大的寬帶;

    一般狀況下,應該配置爲 no 以下降同步的延時,但在主從節點間網絡負載很高的狀況下,能夠配置爲 yes

  • 6. slave-priority

    指定 slave 的優先級,在不僅一個 slave 節點的部署環境下,當 master 宕機時,redis-sentinel 會將 priorty 值最小的 slave 提高爲 master 。\
    須要注意的是,若是該配置項值爲 0,則對應的 slave 永遠不會提高爲 master

主從複製進階常見問題解決

讀寫分離

  • 流量分攤到從節點,這是個很是好的特性,若是一個業務只須要讀數據,那麼能夠創建一臺從機進行讀數據操做
  • 雖然讀寫有優點,可以讓讀這部分分配給各個從節點,若是不夠直接添加 slave 從節點,可是會出現如下問題

    • 複製數據延遲

      • 可能出現 從節點同步數據不及時,致使數據不一致的問題,固然可使用監控偏移量,若是 offset 超出偏移量,就切換到 master 機器上,邏輯切換,具體延遲多少可使用 info replication 命令查看 offset 指標進行排查
      • 對於沒法容忍大量延遲的場景,能夠編寫外部監控程序,「如consul」監聽主從節點的複製偏移量,當延時較大時出發報警,或通知客戶端,避免讀取延時太高的節點
    • 對於N個從節點鏈接的時候才容許寫入「比較極端的方式」

      • Redis2.8 之後,能夠設置主節點只有在N臺從節點鏈接的時候能夠寫入請求。\
        然而,由於 redis 使用的是異步複製,全部沒有辦法保證從節點確實收到的給定的寫入請求,因此存在一個窗口期的數據丟失的可能性。
      • 解釋如下這個特性是怎麼工做的

        • 從節點每秒都會 Ping 主節點,告知它全部的複製流工做。主節點會記住從每一個從節點收到的最新的 Ping
        • 用戶能夠給主節點配置一個在等於從節點的數量的最低值和不超過最高值之間的延遲,若是至少有N個從節點,若是少於延遲M秒,則寫入將被接受。
        • 可能以爲經最大努力保證數據安全的機制,雖然數據一致性沒法保證,可是至少只是幾面的時間窗口內丟失數據,一般狀況下範圍數據丟失可比無範圍數據丟失好多了
        • 若是條件不知足,主節點將會返回一個錯誤,而且寫入請求將不被接受
        • 主節點配置須要兩個參數

          • min-slaves-to-write
          • min-slaves-max-lag
    • 從節點故障問題

      • 對於從節點的故障問題,須要在客戶端維護一個可用從節點列表,當從節點故障時,當即切換到其餘從節點或主節點

主從配置不一致

  • 常常致使主機和從機的配置不一樣,並帶來問題
  • 主機和從機有時候會發生配置不一致的狀況,

    例如:maxmemory 不一致,若是主機配置 maxmemory 爲8G,從機 slave 設置爲 4G,這個時候是能夠用的,還不會報錯,單數若是要作高可用,讓從節點變成主節點的時候,就會發現數據已經丟失了,並且沒法挽回

規避全量複製

  • 全量複製指的是,當 slave 從機斷掉並重啓後,runid 產生變化而致使須要在 master 主機裏拷貝所有數據,這種拷貝所有數據的過程很是耗資源
  • 全量複製是不可避免的。

    例如:第一次的全量複製是不可避免的,這時須要選擇小主節點,且 maxmemory 值不要過大,這樣就會比較快,同時選擇在低峯值的時候作全量複製

  • 形成全量複製的緣由

    1. 主從機的運行 runid 不匹配。
主節點若是重啓,runid 將會發生變化,若是從節點監控到 runid 是不一樣一個,它就會認爲你的節點不安全,當發生故障轉移的時候,若是主節點發生故障,那麼從機就會變成主節點。

1.  複製緩衝區空間不足。

好比默認值:1M 能夠部分複製,但若是緩衝區不夠大的話,首先須要網絡中斷,部分複製就沒法知足,其次須要增大複製緩衝區配置「relbacklogsize」,對網絡的緩衝加強

解決方案:

-   在一些場景下,可能但願對主節點進行重啓。

例如:主節點內存碎片率太高,或者但願調整一些只能在啓動時調整的參數,若是使用普通的手段重啓主節點,會使得 runid 發生變化,可能致使沒必要要的全量複製

-   爲了解決這個問題,redis 提供了 debug reload 的重啓的方式,重啓後,主節點的 runid 和 offset 都不受影響,避免了 全量複製

3.當一個主機下面掛了不少個 slave 從機的時候,主機master 掛了,這時 master 主機重啓後,由於 runid 發生了變化,全部的 slave 從機都要作一次全量複製,這將引發但節點和但機器的複製風暴,開銷會很是大

-   解決方案:

    -   通常使用一主多從,由於主節點還同時擔任寫操做
    -   能夠採用樹狀結構下降多個從節點對主節點的消耗
    -   從節點採用樹狀結構很是有用,網絡開銷給位於中間層的從節點,而沒必要消耗頂層的主節點,可是這種樹狀結構也帶來了運維的複雜性,增長了手動和自動處理故障轉移的難度\

        ![](https://raw.githubusercontent.com/xiaoshuaizhou/pic/master/pic/樹狀結構.png)

規避複製風暴

  • 解決方案:

    • 因爲 redis 的單線程架構,一般單臺機器會部署多個 redis 實例,當一臺機器上同時部署多個主節點「master」時,若是每一個 master 主機只有一臺 slave 從機,那麼當機器宕機之後,會產生大量的全量複製,這種狀況是很是危險的,帶寬立刻被佔用,會致使不可用
    • 應該把主節點儘可能分散在多臺機器上,避免在單臺機器上部署過多的主節點。當主節點所在的機器故障後提供故障轉移機制,避免機器恢復後進行密集的全量複製

如何選擇,要不要讀寫分離

沒有最合適的方案,只有最合適的場景,讀寫分離須要業務能夠容忍必定程度的數據不一致,適合讀多寫少的業務場景,讀寫分離,是爲了要創建一主多從的架構,才能橫向任意擴展 slave node 去支撐更大的讀吞吐量

相關文章
相關標籤/搜索