Redis學習筆記(二):Redis集羣

集羣經過分片(sharding)來進行數據共享,並提供複製和故障轉移功能。
 
1.節點
一個節點就是一個運行在集羣模式下的Redis服務器。啓動Redis服務器時,經過判斷cluster-enabled選項,選擇是否開啓集羣模式。(Yes開啓集羣,No則單機模式普通服務器)
 
一個Redis集羣由多個節點組成,每一個節點使用的端口各不相同,能夠設置。每一個節點最開始能夠看作一個只有本身節點的集羣,節點間經過命令相互握手,組建集羣
 
握手命令
cluster meet 127.0.0.1 7001    //與ip爲127.0.0.1,端口爲 7001的節點握手
cluster nodes      //顯示當前集羣的節點信息

 

2.集羣數據結構
    clusterState 和  clusterNode 以及  slots
 
每一個節點都有  clusterState結構。
clusterState結構的裏面包含 :
            slots[16384]數組,
            myself屬性,(指向本身對應的clusterNode,直接經過該屬性訪問本身對應的clusterNode,這樣更快、方便各類本身節點信息的更新操做)
            nodes屬性,
            slots_to_key跳躍表,
            importing_slots_from[16384]數組(記錄當前節點從其餘節點導入的槽,爲null未導入,指向clusterNode則爲從該clusterNode對應的節點導入槽i)
            migrateing_slots_to[16384]數組(記錄當前節點遷移到其餘節點的槽,對應槽索引的值指向目標節點對應的clusterNode)
 
每一個節點都有一個對應的clusterNode結構。
clusterNode中包含:
            slots數組
            numslot屬性
            slaveof屬性---指向正在複製的主節點的對應clusterNode
            flags屬性---REDIS_NODE_MASTER 表示該節點是主節點
                                REDIS_NODE_SLAVE 表示該節點時從節點
            numslaves---複製該節點的從節點數量
            slaves數組---每一個元素都指向該節點下屬從節點的clusterNode
            
            faile_reports鏈表---記錄其餘節點對該節點的下線報告(在線、疑似下線PFAIL、已下線FAIL)
    nodes字典記錄每一個節點與clusterNode的對應關係
    myself指向屬於該節點對應的clusterNode
 
例:設集羣中目前有7000、700一、7002三個節點。對於7000端口的節點,其擁有一個clusterState結構,三個clusterNode結構(分別對應三個節點),myself屬性指向屬於本身的那個clusterNode節點。
 
 
3.槽指派
 
Redis集羣經過分片的方式來保存數據庫中的鍵值對;集羣的整個數據庫被分爲16384個槽(索引爲0~16383);數據庫中的每一個鍵都屬於槽中的一個。每一個節點都最多處理0~16384個槽。只有這16384個槽都被分配到節點時,Redis集羣才處於上線狀態(ok);不然,只要有任意一個未分配,則集羣處於下線狀態(fail)。
 
槽分配命令
127.0.0.1:7000> cluster addslots 0 1 2 3 ... 5000 //將0~5000的槽分配個7000節點
節點的 clusterState中的 slots[16384]數組,記載着集羣中全部槽的指派信息,即槽是否被指派?被分配給了哪一個節點?
節點的 clusterNode中的 slots數組則使用0-1標記法來表示,該節點處理的槽;處理,則對應槽索引值爲1。使用 numslot屬性記錄該節點處理的槽總數
 
每一個節點除了在本身對應的clusterNode中保存本身的槽分配信息外,還會將本身的slots數組經過消息發送給其餘節點,讓其餘節點保存。即對於7000節點而言,剩下的兩個clusterNode也會根據收到的其餘節點槽相關信息,來更新clusterNode的屬性。(收到消息後,先經過clusterState.nodes查詢對應節點的clusterNode,再對其中的slots數組保存更新)
 
爲何同時使用clusterNode中的slots和clusterState的slots?
這是典型的以空間換時間。
       1. 經過clusterState中的slots[]來查詢槽點是否被指派和指派節點的複雜度爲 O(1);避免了經過nodes字典的映射去依次遍歷clusterNode中的slots[]
       2.clusterNode中的slots[]能夠用於做節點間互相發送槽信息。這樣就直接發送本身對應的clusterNode.slots[]便可,無需對clusterState的slots[]進行遍從來找到本身負責了哪些槽了
 
總結:clusterState.slots[]數組記錄了集羣中全部槽的指派信息;clusterNode.slots[]數組記錄了clusterNode結構所表明節點的槽指派信息。
 
 
4.節點數據庫
 
集羣節點保存鍵值對以及鍵值對過時方式與單機數據庫同樣。
 
節點與單機服務器數據庫方面的一個區別就是:節點只能使用0號數據庫,即db[0](默認服務器啓動時,初始化16個數據庫)
 
clusterState的slots_to_key跳躍表保存 槽 和 鍵 之間的關係 (注意,每一個節點的clusterState的跳躍表,只保存屬於本身節點處理的 槽 和 鍵 的對應關係)
    分值(score)對應 槽號;成員(member)對應 數據庫鍵對象
    用跳躍表保存,方便對某個或某些槽的全部數據鍵進行批量操做
 
 
5.從新分片
 
概念:將任意數量已經指派給某個節點的槽,改成指派給另外一個節點,其中,槽對應的全部鍵值對都須要遷移。
 
特色:一、從新分片是能夠在線進行的,集羣無需下線
          二、 從新分片過程當中,源節點和目標節點均可以繼續處理命令請求(由於從新分片操做是鍵值對不斷的遷移?)
 
操做流程:從新分片操做由Redis的集羣管理軟件 redis-trib 負責執行的  
 
    (對於單個槽的從新分片;多個槽就是單個槽的重複操做?)  
        一、 通知目標節點準備導入屬於槽slot的鍵值對。redis-trip向目標節點發送命令    (導入:import) 會修改目標節點的clusterState.importing_slots_from數組
> cluster setslot <slot> importing <source_id>    //slot爲槽的編號,source_id爲源節點id
        二、 通知源節點準備遷移屬於槽slot的鍵值對。redis-trip向源節點發送命令   (遷移:migrate)    會修改源節點的clusterState.migrating_slots_to數組
> cluster setslot <slot> migrating <target_id>    //target_id爲目標節點id
        三、 從源節點處獲取屬於槽slot的鍵值對。redis-trip向源節點發送命令
> cluster getkeysinslot <slot> <count>            //count爲最多獲取count個鍵值對
        四、 將得到的鍵值對從源節點遷移到目標節點。對於得到的每個鍵值對,redis-trip都向源節點發送一個migrate命令
> migrate <target_id> <target_port> <key_name> 0 <timeout>    //目標節點id、端口、鍵名、超時時間設置

        五、重複三、4兩步操做,直到屬於槽slot的全部鍵值對都成功從源節點遷移至目標節點node

        六、 所有遷移成功後,將槽slot指派給目標節點。redis-trip向集羣中任意一個節點發送命令,將slot指派給目標節點,
> cluster setslot <slot> NODE <target_id>         //正式指派槽slot給界目標id的節點
    而後這個信息會經過消息發送到整個集羣,最終全部節點都會知道這個消息
(指派成功後,經過消息發送,通知整個集羣中的節點,而後節點們根據消息,對節點內的clusterState結構和clusterNode結構進行更新?)
 
總結:先通知目標節點準備導入鍵值對,再通知源節點準備遷移鍵值對,而後開始鍵值對的遷移,鍵值對遷移成功後經過命令將槽指派給目標節點。鍵值對的遷移分爲:從源節點獲取鍵值對(1次最多獲取count個),使用migrate命令將鍵值對從源節點遷移到目標節點,重複操做,直到鍵值對遷移完畢
 
    需注意的是:若是經判斷髮現槽中沒有保存鍵值對,則兩步準備後直接將槽指派給目標節點便可。
 
 
6.命令執行流程(是否處理該槽,是否存在鍵,是否正在遷移,是不是ASK命令轉向過來的等知識點)
 
流程圖:
 
1. 根據算法計算給定鍵key屬於哪一個槽。值爲i
CRC16(key) & 16383   //CRC校驗和 + &16383計算出一個位於0~16383之間的整數
 
2.  判斷該槽是否屬於本節點的處理範圍
    經過clusterState.slots[i] == clusterState.myself 來判斷
 
3.1  該槽在處理範圍,則從當前節點的數據庫中查找鍵
 
    3.1.1 查找到鍵,則執行命令
 
    3.1.2 找不到鍵,則判斷該節點 是否正在遷移該槽(經由clusterState.migrating_slots_to[16384]數組判斷)
 
        3.1.2.1 節點沒有遷移該槽,則向客戶端返回鍵查找不到錯誤。
 
        3.1.2.2 節點正在遷移該槽,則向客戶端返回 ASK錯誤
> ASK i <ip>:<port>               //i爲鍵所在槽,ip和port分別爲從新分片的目標節點的地址和端口    
            注意,ASK錯誤實際是不可見的
 
        3.1.2.3 客戶端根據ASK錯誤,轉向找到遷移的目標節點
 
        3.1.2.4 轉向後,先向目標節點發送 ASKING命令
 
        3.1.2.5 發送ASKING命令後,再從新發送執行命令
 
3.2  該槽不在處理範圍,判斷客戶端是否帶有 ASKING標識(便是否先發送了 ASKING命令
 
    3.2.1 發送了ASKING標識,則破例執行關於該槽的命令一次 
 
    3.2.2 沒有事先發送ASKING命令,則向客戶端返回 MOVED錯誤,形式以下
> MOVED i<鍵所在的槽> <ip>:<port>  //後面爲負責處理該槽的節點的 ip和port
        注意,MOVED命令實際是不可見的。只有單機數據庫下,客戶端沒法讀懂該命令纔會顯示
 
        3.2.2.2 客戶端根據MOVED命令進行 轉向,轉到指定節點,並執行命令
            
 
 
7.ASK錯誤和MOVED錯誤比較
 
相同:都會致使客戶端轉向,都是不可見的。客戶端根據錯誤的信息自動轉向
 
不一樣:1.MOVED錯誤表明將槽的負責權從一個節點轉移到另外一個節點,即永久轉向;下次客戶端遇到一樣槽的命令會直接訪問MOVED指向的節點
 
          2.ASK錯誤只是兩個節點在遷移槽的過程當中使用的一種臨時措施,下次客戶端遇到一樣槽的命令,仍然訪問源節點(即目前負責節點)
            直到槽遷移完成,再次訪問就會收到MOVED命令
 
 
8.從節點,主節點,故障檢測,故障轉移(包括選取新主節點)
 
主節點負責處理槽,從節點用於複製某個主節點;當主節點下線時,在其全部從節點中選取一個用做主節點(相似備份?)(由Sentinel系統監控)
 
設置從節點
> cluster replicate <node_id>    //接收命令的節點成爲從節點,node_id爲其主節點的id
設置從節點後,從節點對應的clusterNode的slaveof指針、flags屬性作出相應修改;主節點的slaves指針數組、numsslaves屬性也更新
 
集羣中的節點之間經過互相發送消息的方式來交換集羣中各個節點的狀態信息
        
故障檢測:節點間按期發送PING消息,以檢測對方是否在線;在線,則應在規定時間內返回PONG消息;
                超時未返回,則標記爲疑似已下線(PFAIL)並更新對方節點對應的clusterNode的fail_reports鏈表(下線報告鏈表)
 
狀態:在線、疑似已下線、已下線(FAIL)
 
當集羣中一半以上主節點都將某個主節點X報告爲疑似已下線時,則認爲該主節點X已下線,並向集羣廣播關於其下線的FAIL消息,讓其餘節點將主節點X標記爲已下線
 
故障轉移
        一、從複製該主節點的全部從節點裏選出一個從節點
        二、該從節點執行 Slaveof no one 命令,成爲新主節點
        三、新主節點撤銷所喲對已下線主節點的槽指派,將這些槽指派給本身
        四、新主節點向集羣廣播一條PONG消息,通知其餘節點本身已成爲新主界定啊,讓其餘節點更新對應的clusterNode中的slots[]等屬性
        五、新主節點開始接受和處理相關命令請求
 
如何選取新主節點
        選舉產生的。 基於Raft算法。(Sentinel系統的領頭Sentinel選舉也採用這種方式)
        
        涉及 (1)集羣的配置紀元,是一個自增計數器,初始值爲0;每進行一次故障轉移操做,值+1
                (2)每一個主節點都有一次投票權,而且會把票投給第一個請求它投票的從節點(若是該主節點還未投票)
                (3)從節點發現主節點下線後,會廣播一條消息,向全部主節點請求得到投票支持
                (4)主節點若向某個從節點投票,則投票同時會發送一條消息
                (5)從節點對收到的消息進行統計
                (6)設集羣中有N個具備投票權的主節點,則當某個從節點收集到 N/2 + 1 張票時,該從節點成爲新主節點
                (7)若沒有知足要求的從節點,則進入一個新的配置紀元,再次選舉。
 
 
9.集羣中的消息發送
 
集羣中的節點經過發送消息和接收消息來進行通訊。發送消息的節點爲發送者sender,接收消息的節點爲接收者receiver
 
常見的五種消息
  • MEET消息:發送者接收到客戶端的 cluster meet 命令後,向指定節點發送MEET消息,邀請該節點進入發送者所在集羣。
  • PING消息:用於檢測節點是否在線。發送該消息有兩種狀況:(1)集羣中每一個節點默認每一秒胡會從已知節點中隨機選取5個節點,並從5個節點中選取最長時間未發送過PING消息的節點發送PING消息。(2)若是節點A最後一次收到節點B的PONG消息時間距當前時間,已超過節點A的cluster-node-timeout設置時長的一半,則A向B發送PING消息,以防止更新滯後
  • PONG消息:接收者收到MEET消息或PING消息後,向發送者返回PONG消息,以通知發送者這條消息已到達。
  • FAIL消息:節點下線消息。當節點A判斷節點B已下線時,則廣播關於B的FAIL消息,讓其餘節點更改節點B的狀態爲已下線。
  • PUBLISH消息:當節點收到PUBLISH命令時,執行命令同時廣播PUBLIS消息,全部節點都執行相同的PUBLISH命令。
相關文章
相關標籤/搜索