reids筆記4 集羣

主從機制

基本原理

CAP原理:

  • Consistent:一致性
  • Availability:可用性
  • Partition tolerance:分區容忍性

網絡分區:分佈式節點網絡斷開的場景。

CAP基本原理是:當網絡分區發生時,不能同時保證一致性和可用性。

redis支持主從同步和從從同步:

replicate
replicate
replicate
replicate
master
slave
slave
slave
slave

redis的主從數據是異步的,分佈式的redis不滿足一致性;主從網絡斷開的時候,主節點仍然可以提供服務,因此滿足可用性。redis滿足最終一致性,從節點會努力追趕主節點,最終兩者狀態一致。

同步機制

增量同步

  • 主節點有一個環形隊列,用於存儲改變內存狀態的值
  • 主節點會在隊列中不斷寫入改變自己狀態的指令
  • 指令不斷髮送給從節點進行同步

注意:如果寫入速度超過讀取速度,則環形隊列值會被新的數據覆蓋

快照同步

  • 主節點進行bgsave,輸出存儲到磁盤
  • 發送快照到對應的從節點
  • 從節點繼續經過增量同步來同步數據

這種方式比較常用,新節點加入redis集羣時,也是全量加載一次,然後增量加載數據

增量和快照同步時,數據都經過磁盤了

無盤複製:直接遍歷內存數據,然後發送給從節點,速度快但是精度太差。

快照同步會影響正在進行AOF的fsync操作,發生快照同步會推遲fsync的過程,影響主節點的效率。

wait指令會讓redis的異步複製變成同步複製,但是阻塞服務,而且如果網絡分區,則redis節點將永遠阻塞。

哨兵機制

問題背景
主從機制的缺陷:

  • 主從集羣依賴master的活性,如果master崩潰,則從節點無法同步數據
  • 集羣沒有選舉機制,master崩潰後,無法確定新的主節點

問題的本質原因:缺少master奔潰後的選舉很同步機制

解決方案:基本思路是,引入哨兵觀測master健康狀態,如果檢測到master崩潰,則確認新的master,並使用新的master同步集羣數據。

注意,哨兵是配置提供者,而不是代理

引入哨兵後客戶端處理方式

  • 遍歷哨兵集羣,選擇一個可用哨兵服務器。哨兵服務器數據是共享同步的
  • 客戶端從哨兵獲取redis集羣的master的地址,之後與master直接通信
  • 客戶端連接不上master後,主動請求哨兵,獲取新的地址
  • master其它原因出故障,但是客戶端可以與master通信時;哨兵會主動通知客戶端更換

詳細解決方案:
定時監控是解決問題的核心。基本步驟如下:

  • 每隔10s,向主節點發送info命令,獲取集羣的拓撲結構。不需要知道從節點的地址,主節點會把信息都發來。主節點故障時,利用之前的info的信息,從從節點中選擇一個獲取集羣信息。
  • 哨兵節點訂閱__sentinel__:hello頻道,獲取其它哨兵對集羣節點的判斷,也獲取其它哨兵信息;同時也發送自己對集羣節點的判斷。
  • 每隔1s,哨兵向主節點、從節點和其它哨兵節點做心跳檢測
  • 對某個節點,如果最後一次收到的回覆的時間超過配置的時間,則判定爲主觀下線;如果master在客觀下線之前回復了消息,則恢復正常狀態。
  • 足夠多的哨兵認爲master下線後,則master爲客觀下線。
  • master客觀下線後,哨兵集羣選出哨兵的master,讓哨兵master在redis的slave節點選出主節點,然後指定其它節點向該節點複製信息。

參考資料:

  • https://zhuanlan.zhihu.com/p/44474652
  • https://juejin.im/post/5c1b482d6fb9a049dd803f55
  • https://hellokangning.github.io/zh/post/redis-sentinel-client-connection/
min-slaves-to-write 1  # 至少有一個從節點在寫,否則停止服務
min-slaves-max-lag 10  # 10s內沒有收到從節點的反饋,則認爲是異常,配合上面那個

Redis Cluster 集羣

Redis Cluster把所有的數據分爲16384個槽位,槽位的信息存儲在每個節點中,不需要其它的分佈式存儲空間空間來存儲節點。
客戶端請求redis集羣的兩種方式:

  • 簡單方式,直接把請求Key發送到連接的任一個客戶端上。如果key命中了則進行讀寫,否則該服務器會回發MOVE指令和對應的服務器地址x,此時對x服務器操作
  • Smart客戶端:保留服務器的映射表,然後客戶端自己計算對應的服務器地址,併發送。可以定時更新表,也可以當請求失敗時更新。

redis的slot和服務的映射關係:
16384個槽有自己對應的映射關係,然後遷移的時候,只需要移動對應槽中的數據即可。使用slot=CRC16(key)/16384來計算對應的key屬於哪個槽:

redis-trib是redis的遷移工具,遷移單位是槽,遷移的槽處於中間過渡狀態。

單個key的遷移過程:

  • 對當前key執行dump指令序列化
  • 通過“客戶端”向目標節點發送數據
  • restore指令攜帶序列化的內容作爲參數
  • 目標節點反序列化參數
  • 目標節點返回“客戶端”OK內容
  • 當前節點刪除key,完成遷移

遷移的過程是同步的,執行restore指令到刪除key的時候,主線程是阻塞的。如果遷移過程中出現故障,則下次重新連接工具時,會自動遷移。

集羣環境下,避免產生大key,否則遷移會發生阻塞,影響線上服務。

遷移過程中,客戶端訪問流程:

  • 先訪問舊節點,數據存在則直接返回
  • 舊節點數據不在,兩種可能:
    • 數據在新節點
    • 數據根本不存在

對於第二種情況,舊節點返回一個-ASK targetNoodeAddr 的重定向指令,客戶端收到該指令後,去目標節點執行一個不帶參數的ASKING指令,然後再在目標節點執行原來的查詢指令。

遷移沒完成的時候,新節點無法管理有關的key,如果此時直接發送查詢指令,新節點不認可該指令,會向客戶端發送-MOVE指令,讓客戶端再去源節點查詢,如此會形成重定向循環ASKING指令是告訴目標節點,必須執行下面的指令。因此遷移影響效率,原來只需要一個ttl,現在需要3個ttl了。

Redis Cluster提供了cluster-node-timeout,表示節點持續對應的時間失聯時,才認定節點出現故障,並進行主從切換,如果沒有該參數,則網絡抖動可能引起主從頻繁切換。

Redis Cluster是去中心化的,不支持事務,mget等命令會慢,因爲這是拆分到多個集羣執行的。rename等方法也不是原子的,會從源節點轉移到目標節點。

槽位變化感知:
MOVED指令修正槽位,如果客戶端請求的數據不在當前節點,則當前節點返回給客戶端MOVE指令,並帶有目標節點的地址,此時客戶端會刷新自己的映射表。

ASKING指令臨時修正槽位,發生再遷移時候,返回給客戶端asking error。上面提到了,客戶端不會刷新映射表。

2次重試:收到MOVED指令,去新節點時,新節點正在遷移,返回給客戶端ASKING的命令了。一般有多次重試的限制次數,超過拋出異常。

集羣變更感知:

  1. 目標節點掛掉,客戶端拋出ConnectionError,立刻隨機挑選一個節點重試,重試的節點通過MOVED指令通知槽位被分配到了新的節點地址。
  2. 運維手動更改集羣信息,主節點切換到其它節點,並把舊的節點移除出集羣。在舊節點的指令會獲取ClusterDown錯誤,並通知不可用。客戶端關閉所有的連接,清空映射表,向上層報錯。下一條指令來時,會重新初始化信息。

集羣的高可用性
集羣中的每個節點,增加至少一個slave節點作爲備份。當某個節點的master不可用時,添加對應的slave作爲master節點即可。

參考文檔

  • https://www.javazhiyin.com/22957.html
  • https://www.infoq.cn/article/sIRPs21lbMvDAJtqQRJE
  • https://zhuanlan.zhihu.com/p/72056688
  • https://medium.com/@pubuduboteju95/deep-dive-into-redis-clustering-1d71484578a9 (推薦)

總結

  • redis主從:主從是爲了備份數據,意外情況下可快速恢復
  • redis哨兵:爲了保證集羣的可用性
  • redis集羣:解決單機容量不夠的問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章