1. 程式人生 > >redis 復制 及其工作原理

redis 復制 及其工作原理

運行 清空 16px mysql主從復制 per 取數據 狀態 數據復制 業務場景

在分布式系統中為解決單點問題,通常會把數據復制多個副本部署到其他機器,滿足故障恢復和負載均衡等需求,redis使用復制功能來保證了高可用

建立復制  

  復制的redis節點分為主節點(master)和從節點(slave),主從對應是一對多的關系,配置方式有三種

  1. 在配置文件中加入 slaveof {masterHost} {masterport} 隨redis啟動生效

  2. 在redis-server啟動命令後加入 --slaveof {masterHost} {masterPort} 生效

  3. 直接使用命令 slaveof {masterHost} {masterPort} 也可用來切換新的主節點(切換後從節點會清空原來的所有數據)

   info replication 可以查看復制節點的信息

   slaveof no one 斷開復制,從節點晉升為主節點

  傳輸延遲

    主從節點一般部署在不同機器上,復制時的網絡延遲必須要考慮到,redis提供的參數repl-disable-tcp-nodelay 用於控制是否關閉TCP_NODELAY 默認為no 關閉

     當關閉時:主節點產生的命令數據無論大小都會及時發送給從節點,這樣主從之間延遲會變小,但增加了網絡帶寬的消耗,適用於主從之間的網絡環境良好的情況,如同機房部署

     當開啟時:主節點會合並較小的tcp數據包,從而節省帶寬,但是延遲會變大,適用於主從網絡環境復制或帶寬緊張的情況,如異地部署

原理

  在從節點執行slaveof 後,過程如下

    1.保存主節點信息

      執行slaveof後從節點只保存主節點的地址信息後便直接返回,此時建立復制的流程還沒有開始

    2.從節點內部通過每秒運行的定時任務維護復制相關的邏輯,當定時任務發現存在新的主節點後,會嘗試與該主節點建立網絡socket連接 (如果從節點無法建立連接,定時任務講無限期重試,直到成功)

    3.發送ping命令,嘗試第一次與主節點通信,主要目的是檢測主從網絡socket是否可用和主節點當前是否可接受處理命令

      如果沒有收到主節點的pong回復或者超時,從節點會斷開復制連接,下次定時任務時重試

    4.權限驗證。如果主節點設置了requirepass 參數,則需要密碼驗證,從節點必須配置masterauth 參數保證與主節點相同的密碼才能通過驗證,驗證失敗,復制終止

    5.同步數據集。主從復制連接正常通信後,對於首次建立的復制場景,主節點會把所有的數據全部發送給從節點,耗時最長

    6.命令持續復制(異步)。有寫命令時,持續同步到從節點

  數據同步

  redis在2.8後采用復制命令psync進行數據同步 (psync {run_id} {offset})

    全量復制: 一般用於首次復 制,當數據量較大時,會對主從節點和網絡造成很大開銷

     部分復制:用於處理在主從復制中因網絡閃斷等原因造成的數據丟失場景,主節點會補發丟失的數據給從節點,可避免全量復制的過高開銷

          部分復制時,psync 需要帶上

          1.主從節點各自的復制偏移量 : master_repl_offset ,slave_repl_offset

          2.主節點的復制積壓緩沖區

          3.主節點運行id run_id ,如果只識別host 和port 那麽當主節點更換RDB文件時,從節點還使用原來的偏移量復制,會造成數據錯誤,,,因此每次主節點重啟時,都會進行全量復制,可使用redis-cli debug reload 每次重啟run_id 不變

  全量復制流程

  1. 發送psync同步命令,第一次沒有主節點運行ID會默認為?,沒有復制偏移量默認為-1 。所以發送psync ? -1
  2. 主節點解析出命令為全量復制,回復 +FULLRESYNC響應,帶上run_id 和offset
  3. 從節點接收到主節點的回復後,保存run_id 和offset
  4. 主節點執行bgsave保存RDB文件到本地
  5. 主節點發送RDB文件給從節點,從節點把接收的RDB文件保存在本地,並直接作為從節點的數據文件(這一步涉及RDB文件的傳輸,如果RDB文件太大,會導致傳輸耗時,超過6G時,可能會導致傳輸時間超過repl-timeout的值,進而從節點會放棄接受RDB文件並清理已下載的臨時RDB文件,導致全量復制識別,建議可調整repl-timeout 的值,默認60秒)
  6. 對於從節點從開始接受RDB快照,到接受 完畢,主節點依然會有讀寫操作,此段時間內,主節點會把寫命令保存在復制積壓緩沖區,當從節點完成接收時,主節點再發送給從節點,保證了主從一致性
  7. 從節點接收完主節點的全部數據後會清空自身舊數據
  8. 清空舊數據後開始加載RDB文件(對於較大的RDB文件,此步驟也是很耗時)
  9. 從節點加載完RDB後,如果當前節點開啟了AOF持久化功能,他會立即做bgrewriteaof 操作,保證了全量復制後AOF立即可用

  心跳

    主從建立復制後,他們之間會維護一個長連接並彼此發送心跳命令

     主對從:ping,從對主:replconf ack {offset}

     1.主從彼此都有心跳檢測機制,可通過client list 查看復制的相關信息

     2.主節點每個10秒發送ping命令,判斷從節點的存活性和連接狀態,可通過repl-ping-slave-period 控制發送頻率

     3.從節點每隔1秒發送replconf ack {offset} 命令,給主節點上報自身當前復制偏移量 ,主節點根據此命令判斷從節點超時時間,通過info replication 中的 lag字段(表示與從節點最後一次通信延遲的秒數)正常延遲在0-1之間

      技術分享圖片

關於在實際中可以遇到的問題

  1.讀寫分離

    主從復制除了做備份以為,最主要的就是用來做讀寫分離,降低單點的壓力

      1.復制延遲

        由於主從復制的異步特性,會導致一段時間內主從數據的不一致問題,這需要業務場景允許短時間數據延遲,對於零容忍延遲,可使用外部程序從主節點的復制積壓緩沖區中取數據,和mysql主從復制中延遲問題的解決方案差不多

      2.讀到過期數據

        當主節點存儲大量的過期數據時,如緩沖數據,redis內部需要維護過期數據的刪除策略

          1.惰性刪除:主節點每次處理命令時,都會檢測鍵是否過期超時,如果超時則執行del刪除命令,之後的del命令也會發送給從節點,為確保主從數據一致性,從節點不會主動刪除過期數據

          2.定時刪除:redis主節點在內部定時任務會采樣一定數據鍵,發現有過期數據鍵時,執行del鍵命令,在大量數據超時並且從節點沒有收到del命令時,在redis3.2版本後,從節點在讀取數據之前會檢測鍵是否過期,來決定是否發送數據

   2.主從配置不一致

    對於有關內存的命令必須主從一致,maxmemory,hash-max-ziplist-entries 等參數

   3.規避全量復制

     1.第一次復制:不可避免,建議低峰時操作

      2.節點運行ID不匹配:如果主節點宕機重啟,會導致run_id 變化,引起全量復制,這種情況要在架構上避免,可使用故障轉移功能,在主節點發生故障後,從節點能晉升為主節點

      3.復制及壓緩沖區不足:主節點網絡中斷後,此時主節點會把寫命令放入復制積壓緩沖區,如果時間長,復制積壓緩沖區內存不夠,導致從節點再次連接時嘗試部分復制,從復制積壓緩沖區找不到偏移量,此時會退化成全量復制,【需要根據網絡中斷時間, 和寫數據量分析出合理的復制積壓緩沖區大小,避免再次連接後找不到偏移量的問題】

    4. 復制風暴問題

      1.單主節點復制風暴

        一個主機上掛載多個從節點情況,當主節點恢復後,導致多個從節點發起全量復制,主節點會創建RDB快照,發送給多個從節點,從而導致主節點的帶寬消耗嚴重變大,造成主從延遲變大,嚴重可能會斷開復制【可架構樹狀結構,減輕主節點的復制壓力】

      2.單機器復制風暴

        單臺機器部署多個redis【多個主從】實例,當這臺機器出現故障或者網絡延遲時,恢復正常後,會有大量從節點對這臺機器的主節點進行全量復制,導致當前機器帶寬消耗,IO消耗,【應該把主節點部署到多臺機器】。【避免恢復後,密集的復制】

      

redis 復制 及其工作原理