經過前幾章,咱們已經瞭解redis從單機版、高併發的主從架構和保證高可用的哨兵模式。可是主從架構的高併發是針對那些讀遠大於寫的場景,若是要保證讀和寫都是高併發的場景呢?那就是能夠使用redis集羣模式。html
redis集羣模式一般是有多個redis節點組成。Redis服務器在啓動時會根據cluster-enabled配置選項是否爲yes來決定是否開啓服務器的集羣模式。node
# cluster-enabled yes cluster-enabled yes
當啓動集羣模式後,在集羣中的每一個節點都會存在一個clusterState數據結構。這個結構記錄了在當前節點的視角下,集羣目前所處的狀態,例如集羣是在線仍是下線,集羣包含多少個節點,集羣當前的配置紀元等信息。以下圖爲node1的clusterState結構。web
在一個三個redis節點組成的redis集羣中,當咱們往該集羣寫入一個命令,那這個命令會被寫入到哪一個節點呢?redis
redis集羣將整個數據庫分爲16384個槽(slot)。每一個redis節點負責其中一部分的槽,當16384個槽都有redis節點負責時,整個redis集羣才能正常工做。算法
爲啥是16384個槽(slot)數據庫
參考博文數組
因此往redis集羣寫入一個命令後,當前節點經過CRC16(key)和&12384計算出一個位於1~16384之間的值,該值決定這對鍵值對屬於哪一個槽。bash
在redis每個節點中都保存在這個一個關於redis集羣的clusterState結構,這個結構包含這個當前這個集羣的相關信息,其中也包含着全部槽的指派信息。服務器
如上圖所示,在一個三個redis節點的集羣中,每個redis節點都存在這clusterState信息。ClusterState結構中有slots屬性,並指向一個大小爲16384的redisNode數組。網絡
命令寫入的流程:
在起初全部槽沒有被指派時,能夠經過執行如下命令將一個或者多個槽指派當前執行該命令的redis節點。
# CLUSTER MEET <slot> [slot...]
CLUSTER MEET 0,1,2,3
槽信息會被保存在redisnode節點結構的slots和numslot屬性中,其中slots是一個二進制數組大小爲16383,該數組的索引正好對應16384個槽,值爲0或1,1就表示該索引對應槽由當前redis節點負責;numslot記錄當前redis節點負責的槽總數。
在一個集羣的中redis節點會相互網絡鏈接發送信息,並告知對方本身在負責哪些槽。其餘redis節點收到信息後,會更新本身的clusterState結構信息,主要是包含所有槽信息的clusterState.slots屬性和clusterState.nodes中對應節點的clusterNode.slots和numslot信息。所以每個redis節點中都保存在完整的槽節點指派信息。
在三個節點的redis集羣,當要給該集羣在增長一個節點node4時,槽在已被所有分配,可是node4須要被分配一部分槽給他,否則node4至關於沒有工做,因此須要從新分片。以node3須要把槽15000~16384從新分配給node4爲例:
當15555槽正在從node3轉移到node4時,會出現一種狀況就是15555槽對應的鍵值對有一部分在node3,另外一部分在node4。當客戶端須要對15555槽下的一個鍵值對的更新時,node3會首先檢查該鍵值對的key是否在當前節點,在就更新,不在返回ask錯信信息,並指引客戶端將該鍵值對寫入node4。
在redis集羣存在主從節點,主節點負責處理槽,從節點負責複製主節點以及當主節點下線時,替代下線的主節點繼續處理槽。
能夠經過一下命令讓接受該命令的節點成爲node_id所指節點的從節點。
cluster replicate <node_id>
執行該命令的流程:
一個節點的成爲從節點,並開始複製主節點的信息會被告知其餘全部全部節點,並去更新全部節點的clusterState中該主節點對應clusterNode結構的slaves和numslaves屬性。
集羣中的每一個節點互相ping其餘節點,當沒有收到有效回覆,就會認定其節點下線。當集羣中有一半的節點認定該節點下線,就會廣播一條消息告知所有節點,將該節點認定爲下線狀態,並開始故障轉移。
故障轉移步驟:
新的主節點選舉基本和在redis的Sentinel模式中選舉領頭Sentinel基本類似,就不在多作詳述能夠翻開redis哨兵模式筆記。
參考:
redis設計與實現