redis cluster模式

經過前幾章,咱們已經瞭解redis從單機版、高併發的主從架構和保證高可用的哨兵模式。可是主從架構的高併發是針對那些讀遠大於寫的場景,若是要保證讀和寫都是高併發的場景呢?那就是能夠使用redis集羣模式。html

節點

redis集羣模式一般是有多個redis節點組成。Redis服務器在啓動時會根據cluster-enabled配置選項是否爲yes來決定是否開啓服務器的集羣模式。node

# cluster-enabled yes
 cluster-enabled yes

當啓動集羣模式後,在集羣中的每一個節點都會存在一個clusterState數據結構。這個結構記錄了在當前節點的視角下,集羣目前所處的狀態,例如集羣是在線仍是下線,集羣包含多少個節點,集羣當前的配置紀元等信息。以下圖爲node1的clusterState結構。web

image-20201117205849712

槽指派

在一個三個redis節點組成的redis集羣中,當咱們往該集羣寫入一個命令,那這個命令會被寫入到哪一個節點呢?redis

redis集羣將整個數據庫分爲16384個槽(slot)。每一個redis節點負責其中一部分的槽,當16384個槽都有redis節點負責時,整個redis集羣才能正常工做。算法

爲啥是16384個槽(slot)數據庫

參考博文數組

因此往redis集羣寫入一個命令後,當前節點經過CRC16(key)和&12384計算出一個位於1~16384之間的值,該值決定這對鍵值對屬於哪一個槽。bash

命令寫入

在redis每個節點中都保存在這個一個關於redis集羣的clusterState結構,這個結構包含這個當前這個集羣的相關信息,其中也包含着全部槽的指派信息。服務器

image-20201118212129185

如上圖所示,在一個三個redis節點的集羣中,每個redis節點都存在這clusterState信息。ClusterState結構中有slots屬性,並指向一個大小爲16384的redisNode數組。網絡

命令寫入的流程:

  1. 首先寫入其中一個節點,該節點開始經過槽分配算法計算槽值M。
  2. 在slots屬性中,redisNode[m]快速定位到該槽負責的節點。
  3. 判斷負責的節點是否爲本身,是執行命令,否返回moved命令(moved : )。該命令包含正確的節點的ip和端口號。
  4. 客戶端接收到moved的錯位信息,將命令發送到正確的節點。

槽維護

在起初全部槽沒有被指派時,能夠經過執行如下命令將一個或者多個槽指派當前執行該命令的redis節點。

# CLUSTER MEET <slot> [slot...]
CLUSTER MEET 0,1,2,3

槽信息會被保存在redisnode節點結構的slots和numslot屬性中,其中slots是一個二進制數組大小爲16383,該數組的索引正好對應16384個槽,值爲0或1,1就表示該索引對應槽由當前redis節點負責;numslot記錄當前redis節點負責的槽總數。

image-20201119203556528
image-20201119203556528

在一個集羣的中redis節點會相互網絡鏈接發送信息,並告知對方本身在負責哪些槽。其餘redis節點收到信息後,會更新本身的clusterState結構信息,主要是包含所有槽信息的clusterState.slots屬性和clusterState.nodes中對應節點的clusterNode.slots和numslot信息。所以每個redis節點中都保存在完整的槽節點指派信息。

image-20201119205629055
image-20201119205629055

從新指派

在三個節點的redis集羣,當要給該集羣在增長一個節點node4時,槽在已被所有分配,可是node4須要被分配一部分槽給他,否則node4至關於沒有工做,因此須要從新分片。以node3須要把槽15000~16384從新分配給node4爲例:

  1. 開始對15000槽從新分配。
  2. node4準備導入屬於15000槽的鍵值對。
  3. node3準備遷移屬於15000槽的鍵值對。
  4. 若是node3存在15000槽的鍵值對,將這些鍵值對導入node4。
  5. 將槽指派給node4,完成對15000槽的從新指派。
  6. 其餘槽的從新指派重複以上步驟。

當15555槽正在從node3轉移到node4時,會出現一種狀況就是15555槽對應的鍵值對有一部分在node3,另外一部分在node4。當客戶端須要對15555槽下的一個鍵值對的更新時,node3會首先檢查該鍵值對的key是否在當前節點,在就更新,不在返回ask錯信信息,並指引客戶端將該鍵值對寫入node4。

複製和故障轉移

在redis集羣存在主從節點,主節點負責處理槽,從節點負責複製主節點以及當主節點下線時,替代下線的主節點繼續處理槽。

複製

能夠經過一下命令讓接受該命令的節點成爲node_id所指節點的從節點。

cluster replicate <node_id>
image-20201120203013924

執行該命令的流程:

  1. 接收到該命令的節點首先會在本身的clusterState.nodes字典中找到node_id所對應節點的clusterNode結構,並將本身的clusterState.myself.slaveof指針指向這個結構,以此來記錄這個節點正在複製的主節點。
  2. 修改本身的clusterNode屬性flags爲REDIS_NODE_SLAVE和saveof屬相指向主節點clusterNode1。
  3. 從節點調用複製代碼,複製主節點。

一個節點的成爲從節點,並開始複製主節點的信息會被告知其餘全部全部節點,並去更新全部節點的clusterState中該主節點對應clusterNode結構的slaves和numslaves屬性。

image-20201120204327179

故障轉移

集羣中的每一個節點互相ping其餘節點,當沒有收到有效回覆,就會認定其節點下線。當集羣中有一半的節點認定該節點下線,就會廣播一條消息告知所有節點,將該節點認定爲下線狀態,並開始故障轉移。

故障轉移步驟:

  1. 在下線主節點的全部從節點裏面選擇一個從節點。
  2. 被選中的從節點會執行SLAVEOF no one命令,成爲新的主節點。
  3. 新的主節點會撤銷全部對已下線主節點的槽指派,並將這些槽所有指派給本身。
  4. 新的主節點向集羣廣播一條PONG消息,這條PONG消息可讓集羣中的其餘節點當即知道這個節點已經由從節點變成了主節點,而且這個主節點已經接管了本來由已下線節點負責處理的槽。
  5. 新的主節點開始接收和本身負責處理的槽有關的命令請求,故障轉移完成。

新的主節點選舉基本和在redis的Sentinel模式中選舉領頭Sentinel基本類似,就不在多作詳述能夠翻開redis哨兵模式筆記。

參考:

redis設計與實現

相關文章
相關標籤/搜索