06 數據同步:主從庫如何實現數據一致

本篇重點

主從庫同步原理、如何應對主從庫間網絡斷連風險

主從庫同步:全量複製、基於長連接的命令傳播、增量複製——應對主從庫間的網絡斷連

背景

若Redis只有一個實例運行,當該實例服務宕機後,宕機這段時間內Redis無法爲新來的數據請求提供服務。

Redis採取的解決方案是——增加副本冗餘量,即將一份數據同時保存在多個實例上——Redis主從庫模式

多實例保存同一份數據,需要考慮的問題:

  • 副本間的數據如何保持一致?——數據同步
  • 數據讀寫操作可以發給所有實例嗎?——數據讀寫

前言

Redis高可靠性的保證

  • 數據儘量少丟失——持久化存儲(AOF/RDB)
  • 服務儘量少中斷——主從庫(本質是增加副本冗餘量)

Redis主從庫模式

  • Redis主從庫模式:保證數據副本一致性,且主從庫 “讀寫分離”
  • 讀寫分離:
    • 讀操作:主從庫都可接收
    • 寫操作:主庫接收並執行,然後由主庫將寫操作同步給從庫
    • 主從庫讀寫分離
      主從庫讀寫分離
  • 主從庫同步的三個問題:
    • 實現原理——如何完成主從庫
    • 主庫數據是一次性傳給從庫,還是分批同步?
    • 主從庫間網絡斷連了,數據還能保持一致嗎?

1. 主從庫第一次同步

  • replicaof命令——建立主從庫關係[1]
    • 某Redis實例執行:replicaof 主庫IP 主庫port
    • 該實例與主庫建立主從庫關係,成爲主庫的從庫
  • 主從庫第一次同步的三個階段(某實例第一次執行replicaof與主庫建立連接)
    • 建立連接,協商同步
      • 從庫->主庫:psync
      • 主庫->從庫:FULLRESYNC
    • 數據同步
      • 主庫->從庫:RDB快照
      • 從庫:清楚舊有數據,加載RDB
      • 主庫在數據同步中,執行完RDB後,正常接收 & 執行的寫操作會被寫入 replication buffer 中
    • 同步數據同步期間到來的寫操作——replication buffer
      • 主庫->從庫:replication buffer
      • 從庫:重新執行replication buffer中的操作
  • Redis第一次主從同步流程
    Redis第一次主從同步流程
  • 命令及參數解釋:
    • psync命令形式:psync runID offset
    • runID:Redis實例ID,首次連接主庫ID未知,傳?
    • offset:複製進度,第一次複製傳-1
    • FULLRESYNC: 全量複製,第一次建立連接採用全量複製

Q:主從庫同步中,主庫執行RDB快照時,需要fork bgsave子進程,若從庫數量很多,則主庫fork的壓力就會增加,如何應對這種問題?緩解主庫壓力?

A:主從級聯模式——“主—從—從”,在從庫間建立“主從”關係,分擔主庫全量RDB的壓力

2. 主從級聯模式:分擔全量複製時的主庫壓力

  • “主—從—從”模式:選擇一個從庫(內存配置較高),級聯其他從庫(replicaof)

3. 基於長連接的命令傳播——避免頻繁建立連接

  • 主從庫建立網絡連接後,此時主從庫間已經完成了一次全量複製,後續Redis實例會維護這個網絡連接,在這個網絡連接上進行 “寫操作同步”
  • “主—從—從”模式
    “主—從—從”模式

4. 增量複製——主從網絡斷連後的解決方案

增量複製——僅同步斷連期間主庫收到的命令

repl_backlog_buffer——環形緩衝區,存儲主庫收到的寫命令——記錄主/從的寫/讀進度,通過offset

  • master_repl_offset:主庫寫offset,遞增值
  • slave_repl_offset: 從庫讀offset,遞增值
  • 主從庫連接期間,master_repl_offset == slave_repl_offset
  • 主從庫斷連後,master_repl_offset >= slave_repl_offset

Redis增量複製流程

  • 斷連期間
    • 主庫->replication buffer: 存儲寫命令(用於寫操作同步)
    • 主庫->repl_backlog_buffer: 存儲寫命令
    • 主庫:記錄 master_repl_offset
  • 連接恢復時
    • 從庫->主庫: psync 主庫runID slave_repl_offset
    • 主庫->從庫:slave_repl_offset之後的寫命令(全量/增量)
    • 從庫:執行這些寫命令
  • Redis增量複製流程
    Redis增量複製流程

Q: 主庫寫入速度快,從庫讀取慢,導致未讀的命令被新寫的命令覆蓋,引起的主從庫數據不一致問題如何預防?

A:

  • 調整 repl_backlog_size 大小,通常 = 緩衝空間大小*2
  • 或採用切片集羣分擔單個主庫的請求壓力(將寫請求分散到集羣中)

Q: 主從斷連時間過長,導致slave_repl_offset上的未讀數據已經被新寫入操作覆蓋(同上一個問題),如何數據同步?

A: 主庫採用全量複製

  • 主庫判斷被覆蓋—— master_repl_offset - slave_repl_offset > repl_backlog_size (個人猜想)
  • 若上式成立,則執行全量複製,否則增量複製

Q: 本篇討論的都是“主庫如何同步數據給從庫”、“斷連恢復後主庫如何同步斷連期間的數據給從庫”的問題,那麼當主庫掛了,Redis如何對外提供服務?此時從庫能起到什麼樣的作用?——主從庫模式的重要功能——服務儘量少中斷

A: Redis的哨兵機制[鏈接]

圖片來源於極客時間專欄《Redis核心技術與實戰》


  1. Redis5.0前使用slaveof命令 ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章