1. 程式人生 > >redis入門指南(六)—— 叢集

redis入門指南(六)—— 叢集

寫在前面

  學習《redis入門指南》筆記,結合實踐,只記錄重要,明確,屬於新知的相關內容。

   

配置叢集

  1、配置叢集,叢集解決了單點故障以及單臺機器記憶體上限的問題,使用叢集時,只需要將配置檔案中的引數cluster-enabled開啟即可,叢集中至少有三個主庫才可以執行,當啟動若干個redis-server後,此時每個節點都是獨立的,想要初始化叢集,redis原始碼中提供了一個使用ruby語言編寫的工具,redis-trib.rb來輔助初始化叢集。

  2、使用redis-trib.rb初始化叢集,只需要執行:

redis-trib.rb create --replicas n [ip:port ...]

  create 表示初始化叢集,--replicas n表示每個主庫擁有的從庫數量,執行命令後,會輸出一系列資訊,包含節點的啟動資訊(是否啟動成功),以及主從資訊,如果覺得沒問題,輸入yes來開始建立。

  3、redis-trib.rb會像客戶端一樣嘗試PING每個節點,如果PING失敗則叢集啟動失敗,之後會發送INFO命令獲取每個節點的runid以及是否開啟了叢集;以上就緒後,會向每一個節點發送CLUSTER MEET ip port命令,用來告訴當前節點指定ip和port上執行的節點也是叢集的一部分;接著開始分配主從資料庫,redis-trib.rb會盡量使得主從庫不在同意IP上,以保證容災能力;然後為每一個主庫分配插槽(用來分配哪些鍵由哪個庫儲存),最後向每個要成為從庫的節點發送CLUSTER REPLICATE 主庫runid命令,來將該節點轉換成從庫並複製指定執行id的節點,至此叢集初始化完畢。

  4、叢集初始化完畢後可以使用redis-cli連線任意節點即可獲取整個叢集的資訊(使用CLUSTER NODES命令),也可以嘗試使用redis-cli初始化一次叢集。

 

增加節點

  5、向叢集中增加節點

    CLUSTER MEET ip port

    增加節點時,只需要使用客戶端向新增節點發送該命令;ip 和 port 分別是叢集中已有的某個節點的ip和port。

  6、新增節點你會向叢集中的節點進行握手,握手成功後新節點將被認作叢集的一員,被握手的節點會使用Gossip協議通知叢集中的其他節點關於新增節點的資訊。

 

插槽

  7、redis使用CRC16演算法將每個鍵的有效部分計算出雜湊值對16384取餘,使得每個鍵都可以分配至16384個插槽中;鍵名的有效部分有以下規則:

    a、當鍵名包含{符號,且在其後存在}符號,並且兩者之間至少有一個字元,那有效部分指的是{和}之間的內容。

    b、如果不滿足上一條,整個鍵名都是有效部分。

  8、在使用工具redis-trib.rb初始化叢集時,每個節點會被分配到連續的插槽,但redis並沒有這個限制,可以將任意幾個插槽交給特定的節點負責。

  9、檢視插槽的分配情況

    CLUSTER SLOTS

    返回資訊的數量會是多條,每條資訊中包含槽的開始和結束號碼以及主從資訊。

  10、分配未被分配的插槽

    CLUSTER ADDSLOTS slots [slots ...]

    若分配了已經分配出去的插槽,則會返回錯誤。

  11、若要移動插槽給另外的節點,也可以使用redis-trib.rb工具:

redis-trib.rb reshared ip port

  reshared告訴redis-trib.rb要重新分片,ip和port是叢集中任意節點的地址和埠;之後redis-trib.rb會詢問要遷移多少個插槽,要把插槽遷移到哪個節點(通過執行id確定節點)要從哪個節點移出插槽,最後輸入done即可。

  12、若不借助redis-trib.rb移動插槽,可以使用如下命令:

    CLUSTER SETSLOT 插槽號 NODE 新節點的執行id

    但使用該命令的前提是,插槽中沒有鍵,因為該命令只會遷移插槽,不會遷移鍵,使用如下命令獲取插槽中的鍵:

    CLUSTER GETKEYSINSLOT 插槽號 要返回的鍵的數量

    之後對每個鍵進行遷移,命令如下:

    MIGRATE 目標節點地址 目標節點埠 鍵名 資料庫號碼 超時時間 [copy] [replace]

    copy選項表示不從當前庫中刪除,而是複製一份副本,replace表示如果存在相同鍵名則覆蓋,資料庫號碼始終是0。

  13、以上的方法仍然會造成資料臨時丟失,redis提供瞭如下兩個命令來實現叢集不下線的情況下遷移資料:

    CLUSTER SETSLOT 插槽號 MIGRATING 新節點runid 

    CLUSTER SETSLOT 插槽號 IMPORTING 原節點runid

    redis-trib.rb工具在遷移時就會先執行上面兩條命令,用來解決臨時丟失問題,之後獲取插槽中儲存的鍵,一一遷移,最後遷移插槽。

  14、執行上面的前兩個命令後,當客戶端向原節點要遷移的插槽請求一個鍵時,若該鍵未被遷移,則直接返回,若已遷移,返回ASK跳轉命令告訴客戶端新的節點,客戶端會先向新節點發送ASKING命令,之後重新執行最初的請求鍵的命令;相反,如果客戶端向新節點請求了一個正在遷移的插槽中的鍵,如果前面執行過ASKING命令則直接返回,如果沒有執行過則返回MOVE跳轉命令,重新告訴客戶端到原節點去請求鍵。

  

獲取與插槽對應的節點

  15、對於指定的鍵,會根據CRC16演算法分配到對應的插槽,那麼如何獲知插槽所在的節點,當客戶端請求一個不在當前節點負責的插槽中的鍵時,redis會返回MOVE重定向指令:

    MOVE slot ip port

    包含對應鍵所在的插槽號和該插槽所在的節點的地址和埠,客戶端收到MOVE指令後,再到對應節點請求鍵。

  16、一些語言的redis庫支援MOVE請求,此時對開發者而言這是透明的,使用-c引數啟動redis-cli則會以叢集模式啟動,也支援自動重定向;為解決由於重定向導致的多次的網路請求,客戶端應快取插槽的路由資訊,以達到與單機同樣的效能。

 

故障恢復

  17、叢集中每個幾點會每秒挑選另外五個節點,對其中最久沒有相應的節點發送PING,如果一定時間沒有回覆,發起PING的節點就會認為其疑似下線,與哨兵的主觀下線類似。

  18、一旦節點A認為B疑似下線,就會在叢集中傳遞這個訊息,當某一節點收到半數以上認為B下線的訊息,就會向叢集中傳播B已下線的訊息。

  19、當叢集中有主庫下線,則會導致一部分插槽無法寫入,這時如果主庫擁有至少一個從庫,叢集就會進行故障恢復將一個從庫轉變為主庫;選擇哪個主庫,與選擇領頭哨兵的過程一致,都基於RAFT演算法。

  20、如果至少負責一個插槽且沒有從庫的主庫下線,叢集預設進入下線狀態無法工作,可通過修改配置引數cluster-require-full-coverage為yes來使其在這種情況仍可以工作。

 

叢集的一些限制

  21、當涉及多鍵命令時,如果想關鍵不在同一個節點,則會執行出錯,可以利用鍵名的有效部份這一特點,將要操作的多鍵的鍵名使用{}改造,保證其在同一節點。

  22、叢集中的每個節只能使用0號資料