Redis集羣入門

官方文章:html

https://redis.io/topics/cluster-tutorial#redis-cluster-configuration-parametersjava

 

本文永久地址:node

http://www.javashuo.com/article/p-xpfvwiyc-cr.htmlgit

 

本文檔是Redis集羣的簡單介紹,沒有涉及複雜難懂的分佈式概念的贅述,只是提供了從用戶角度來如何搭建測試以及使用的方法,若你打算使用並深刻了解Redis集羣,推薦閱讀完本章節後,仔細閱讀Redis集羣規範一章。本教程試圖提供最終用戶一個簡單的關於集羣和一致性特徵的描述。github

 

請注意,本教程基於Redis 3.0或更高的版本。若是你計劃部署集羣,那麼咱們建議你從閱讀這個文檔開始。redis

 

Redis集羣基礎

  Redis集羣定義docker

  Redis集羣提供一種redis運行方式,能將數據自動分片到多個Redis節點,且Redis集羣在分區期間也提供必定的可用性,即在某些節點發生故障或沒法通訊時,集羣也能正常工做,但當大面積節點故障,如大多數master都不可用時,集羣就不能使用了數據庫

 

  從實用性角度,Redis集羣提供一下功能:promise

    ·自動切割數據到多個Redis節點緩存

    ·小部分節點故障或者不可達時,集羣能正常工做

 

  Redis集羣TCP端口

  Redis集羣中每一個節點都需偵聽兩個TCP端口,6379端口用於客戶端通訊,客戶端通訊端口加上10000(兩個端口老是相差10000),如16379專用於集羣總線(Cluster bus),用於節點間二進制協議的節點間通訊。各節點使用集羣總線故障檢測,配置更新,故障轉移受權等。客戶端不能使用集羣總線端口

 

  請注意,爲了讓Redis羣集正常工做,須要爲每一個節點配置2個端口(必須):

    ·客戶端端口(默認6379)須要對全部客戶端和集羣節點開放,由於集羣節點須要經過該端口進行密鑰遷移(keys migrations

    ·集羣總線端口(客戶端端口+ 10000)對集羣全部節點開放便可

 

  集羣總線使用不一樣的二進制協議(不一樣於客戶端與Redis使用的協議)進行節點到節點的數據交換,此協議能夠減小帶寬和處理時間

 

  Redis集羣和Docker

  目前,redis集羣並不支持地址和端口都被從新映射的NAT環境

  Docker使用一種端口映射技術:運行在docker容器內部的程序可能使用的端口和客戶端程序使用的端口不一樣,這對於同一服務器中同時使用相同端口運行多個容器頗有用

  爲了使DockerRedis Cluster兼容,您須要使用Docker的主機聯網模式。請查看Docker文檔--net=host選項以獲取更多信息

 

  Redis集羣數據分片

  Redis集羣不使用一致性哈希,而是一種不一樣的分片形式,其中每一個鍵在概念上都是咱們稱之爲哈希槽的部分

  Redis集羣中有16384個哈希槽,每一個key經過CRC16校驗後對16384取模來決定放置哪一個槽。

  集羣中每一個節點負責哈希槽的的一個子集,如一個有3點歌節點的Redis集羣:

    ·節點A包含從05500的哈希槽

    ·節點B包含從550111000的哈希槽

    ·節點C包含從1100116383的哈希槽

 

  如此便能方便地添加和刪除集羣中的節點。如我想添加一個新節點D,我須要將節點ABC中的一些哈希槽移動到D;一樣,想刪除節點A,則能夠移動由A服務的散列槽到BC.當節點A將爲空時,我能夠將它從羣集中完全刪除。

  因爲從一個節點將哈希槽移動到另外一個節點並不會中止服務,因此不管添加刪除或者改變某個節點的哈希槽的數量都不會形成集羣不可用的狀態

 

  若多個key都屬於一個哈希槽,那麼集羣能經過單個命令(或者一個完成的事務或Lua腳本執行)同時操做這些key,咱們可使用「哈希標籤」(Hash tags)強制讓多個key分配到同一哈希槽。「哈希標籤」在Redis集羣規範中有介紹,簡單來講就是若key含有大括號」{}」,則只有大括號中的字符串會被哈希,如「this{foo}another{foo}」這兩個key必定會被分配到同一個哈希槽,而後在具備多個間的命令中做爲參數一塊兒使用。

 

  Redis集羣主從模式

  爲了保證在部分主master節點掛掉或不能與大多數節點通訊時保持可用性,Redis集羣使用主從模式,保證每一個哈希槽都有1個到N個副本。

  上述例子咱們有節點ABC三個,若節點B故障,集羣則再也不可用,且會丟失從550111000哈希槽。然而若每一個master都有一個slave,也就是說ABC三個master節點就會分別有A1B1C1三個slave節點,即便B節點掛掉,集羣也不會受影響,B1複製了B的數據,此時集羣將提高B1做爲新master繼續正常工做。但BB1同時掛掉,redis集羣確定就不可用了。

 

  Redis集羣對一致性的保證

  Redis集羣不能保證強一致性,在架構中這意味着在某些狀況下,可能會丟失向客戶端返回「確認寫成功」的數據

 

  丟失寫入數據的第一個緣由就是redis異步複製數據,也就是說:

    ·客戶端寫入數據到master B

    ·master B向客戶端返回「寫入成功」

    ·master B傳輸數據到slaveB1B2B3

 

  由上可知,B在回覆客戶端以前不等待B1B2B3的寫入完成確認,所以這會對redis形成嚴重的延遲損失,就像客戶端寫入了數據,master B確認寫入,但在B將數據複製到任何一個slave前就已經掛掉,那寫入將永久丟失,由於被提高爲新master的任何slave都沒有收到該數據。

 

  這與大多數每秒刷新數據到磁盤的數據庫配置相似,也能夠經過強制數據庫在回覆客戶端前先刷新數據到磁盤來提升一致性,但這種作法性能不好,這種方式就是讓Redis集羣在使用同步複製。

 

  到底使用哪一種方式,要根據應用場景在性能和一致性之間有一個權衡。

 

  若真的須要,redis集羣也能經過「WAIT」指令實現同步複製,這使得寫入丟失的可能行大大下降,但並不意味着使用同步複製Redis集羣就是強一致性了,如master還將來得及同步數據到任一slave就掛掉,或者被提高爲新master沒有收到同步過來的數據,都會致使不一致性的發生。使用「WAIT」只能相對的提升一致性。

 

  還有一個值得注意的場景發生在網絡故障時,當客戶端與少數節點(至少一個master節點)正常通訊,但與其餘大多數節點網絡不通。以ABCA1B1C1 三主三從組成的6個節點集羣爲例,另一個客戶端稱之爲Z1。網絡故障產生網絡分區後,可能ACA1B1C1在一個分區,而BZ1在另外一個分區。此時B仍然能接收寫入請求,Z1仍然能寫入B。若分區在很短期能恢復,集羣將繼續正常運行,但若網絡過久未恢復,網絡分區持續時間太長,B1會在大多數節點都能通訊的分區裏面被提高爲mastermaster B在網絡恢復後,會成爲master B1的新slave,且丟棄Z1發送給B的寫操做,而後從B1從新複製數據。

 

  節點間網絡通訊斷開有一個時間限制,若斷開時間超過了大多數節點能容忍的長度,那就會有一個新的master被選舉出來。

  這個時間被稱之爲節點超時(node timeout,這個時間對集羣很是重要,當達到節點超時時間,master被認爲已經下線,會有新master被選舉出來。一樣,在節點超時後,若master仍然不能聯繫到其餘master,它將進入錯誤狀態,並中止接收寫入請求。

 

Redis集羣參數配置

  先介紹redis.conf中集羣的參數配置,後面會有集羣部署示例。

    ·cluster-enabled yes/no #Redis集羣開關。Yes表示他是集羣中一個節點,no表示他是一個普通單一的redis實例

    ·cluster-config-file nodes-6379.conf #配置被稱之爲「集羣配置文件」,但此配置文件是集羣節點自動維護,不須要人工干預,每次集羣配置有所變更,都會自動更新到此文件,以便節點重啓時能從新加載配置。該文件列出集羣中其餘節點的狀態,持久化的參數選項等等

    ·cluster-node-timeout 15000 #單位毫秒,集羣節點可以失聯的最大時間,超過該時間,該節點就會被認爲故障。Master超過此時間不可達,它的slave節點就會選舉出新master替代之。另外,任何節點超過此時間沒有與大部分master通訊將中止接收任何請求

    ·cluster-slave-validity-factor 10 #用於限定slavemaster的失聯時長的倍數。若設置0,不管slavemaster失聯多久,slave都會嘗試升級爲master(只要slave沒法與master通信,都會嘗試故障轉移,Cluster有選舉機制,有可能會被否決),若設置爲正數,則失聯的最大時長爲(cluster-node-timeout * cluster-slave-validity-factor),超過此時間slave不具有故障轉移資格,沒法被提高爲master。如cluster-node-timeout5scluster-slave-validity-factor10,,當slavemaster失聯超過50s後,slave就再也不具有成爲master的資格。注意,若是此參數不爲0,可能出現因爲某master節點失聯卻沒有slave能頂上的狀況,從而致使集羣不能正常工做,此時,只有等到原來的master從新迴歸到集羣,集羣才恢復正常。

    ·cluster-migration-barrier 1 #此參數保證Redis集羣中不會出現裸奔的master節點,即保證每一個master節點都有slave節點。只有當一個master節點至少擁有給定數量個處於正常工做中的slave節點時,纔會分配slave節點給集羣中孤立的master節點。這個給定數量就是cluster-migration-barrier。給定數量是1意味着一個slave節點只有在其master節點另外至少還有一個正常工做的slave節點的狀況下才會被分配(副本遷移)。那些分配後仍然剩餘migration barrierslave節點的master節點纔會觸發副本遷移,而不是分配前有migration barrierslave節點的master節點會觸發節點分配!!有關教程,請參閱本文檔副本遷移部分

    ·cluster-require-full-coverage yes #在部分key所在的節點不可用時,若是此參數設置爲」yes(默認值), 則整個集羣中止接受操做;若是此參數設置爲」no」,則集羣依然爲可達節點上的key提供讀操做(集羣是否須要全部的slot都分配給在線節點才能正常訪問)

 

建立和使用Redis集羣(主要兩步驟:建立實例和鏈接實例建立集羣)

  注意:手動部署一個redis集羣,最主要是在學習各類操做。

  若想盡快啓動並運行一個集羣,能夠直接看下一節「使用create-cluster腳本直接建立Redis羣集」

 

  要建立一個redis集羣,首要任務就是以集羣模式運行幾個空Redis實例,必須以集羣模式運行,才能使Redis實例具備集羣節點功能、支持集羣節點指令

  如下是最小redis集羣配置文件:

  port 7000

  cluster-enabled yes

  cluster-config-file nodes.conf

  cluster-node-timeout 5000

  appendonly yes

  

 

  Redis集羣正常運行至少須要3master對於第一次測試,建議啓動一個由三主三從組成的六節點羣集:

 

  一、建立6個以redis實例端口名稱的目錄:

        mkdir -pv /usr/local/cluster-test/700{0..5}

  二、在每一個端口號目錄下建立配置文件redis700{0..5}.conf,內容爲上面最小redis集羣配置,注意修改端口號

  三、啓動6redis集羣節點,建議啓動6個終端分別啓動:

    cd /usr/local/cluster-test/7000 ; redis-server /usr/local/cluster-test/7000/redis7000.conf &
    cd /usr/local/cluster-test/7001 ; redis-server /usr/local/cluster-test/7001/redis7001.conf &
    cd /usr/local/cluster-test/7002 ; redis-server /usr/local/cluster-test/7002/redis7002.conf &
    cd /usr/local/cluster-test/7003 ; redis-server /usr/local/cluster-test/7003/redis7003.conf &
    cd /usr/local/cluster-test/7004 ; redis-server /usr/local/cluster-test/7004/redis7004.conf &
    cd /usr/local/cluster-test/7005 ; redis-server /usr/local/cluster-test/7005/redis7005.conf &

  

    因爲每一個實例都是新啓動的,nodes.conf尚未自動生成,因此會發出此信息,且生成nodes.conf,都會爲本身分配一個新的ID

    10390:M 31 May 14:33:58.078 * No cluster configuration found, I'm f219739744e2fca6f2e6e6c75c9c1f2caa95b05b

 

    做爲此節點在整個集羣中的惟一標識,生成的ID將一直被各節點使用,節點使用ID來區分其餘節點而非IP+PORT,這個ID在節點的整個生命週期內都不會改變,除非節點被移除集羣。這個ID咱們稱之爲節點IDNode ID

 

  四、此時6個集羣模式的Redis實例已經運行,能夠開始建立Redis集羣。Ruby腳本「redis-trib」是一個可讓咱們很是方便地建立Redis集羣的命令行工具,該腳本用於建立新集羣,狀態檢查,或給集羣從新分片:

 

     yum install rubygems ruby
     gem install redis #若提示ruby版本太低,請查看 https://www.cnblogs.com/erbiao/p/9117018.html  。另外,若你的redis版本是4.0.X,強烈建議安裝低版本的redis版本庫,不然reshard時會出現語法錯誤。具體請查看:https://www.cnblogs.com/erbiao/p/9138604.html
     redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 #「--replicas 1」表示每一個master節點須要一個slave節點。其餘參數就是須要加入這個集羣的redis實例的地址。執行後,redis-trib會提供一些建議的配置。       

    ... ...

    [OK] All nodes agree about slots configuration.

    >>> Check for open slots...

    >>> Check slots coverage...

    [OK] All 16384 slots covered. #表示有16384個哈希槽可用

 

    顯示如上信息表示集羣建立完成

  五、查看nodes.conf信息

    cat /usr/local/cluster-test/7001/nodes.conf

    06c5baf38ae368bbe8b7fef037d42026ab385590 127.0.0.1:7001@17001 myself,master - 0 1527753131000 2 connected 5461-10922

    fdc0c79f9f782b218dad297b48bde32aa0acc31f 127.0.0.1:7005@17005 slave 3fbbebd7bd822dfada7db5bde983534ff2906d4f 0 1527753131000 6 connected

    b88654ae05706a771d6f23d8877e890f99dba315 127.0.0.1:7004@17004 slave 06c5baf38ae368bbe8b7fef037d42026ab385590 0 1527753131000 5 connected

    41ec008599691424cdf8cdf9f3dc26ab1eef7050 127.0.0.1:7003@17003 slave f219739744e2fca6f2e6e6c75c9c1f2caa95b05b 0 1527753131600 4 connected

    f219739744e2fca6f2e6e6c75c9c1f2caa95b05b 127.0.0.1:7000@17000 master - 0 1527753131000 1 connected 0-5460

    3fbbebd7bd822dfada7db5bde983534ff2906d4f 127.0.0.1:7002@17002 master - 0 1527753130599 3 connected 10923-16383

    vars currentEpoch 6 lastVoteEpoch 0

 

使用腳本create-cluster建立redis集羣

  上述的建立方法比較繁瑣,「utils/create-cluster/create-cluster」此腳本能簡化建立步驟,此腳本會調用其餘redis集羣命令,因此最好在utils/create-cluster中執行,或者修改腳本文件也是能夠的。

  腳本utils/create-cluster/create-cluster」有默認參數,能夠根據須要從新定義。

 

  如要啓動一個三主三從6節點的Redis集羣:

  1、命令默認生成6個集羣模式的Redis實例,端口30001 ~ 30006

  cd utils/create-cluster/
   ./create-cluster start

 

  2、鏈接各個實例,建立Redis集羣

  cd utils/create-cluster/
  ./create-cluster create

 

    [OK] All 16384 slots covered. #表示建立成功

 

  三、默認生成的文件都在當前目錄,包括持久化AOF文件,日誌文件,RDB數據文件(手動也會生成)

    [root@hd4 create-cluster]# ll

    總用量 92

    -rw-r--r-- 1 root root 2518 5月  31 16:27 30001.log

    -rw-r--r-- 1 root root 3683 5月  31 16:27 30002.log

    -rw-r--r-- 1 root root 3683 5月  31 16:27 30003.log

    -rw-r--r-- 1 root root 4739 5月  31 16:27 30004.log

    -rw-r--r-- 1 root root 4739 5月  31 16:27 30005.log

    -rw-r--r-- 1 root root 4739 5月  31 16:27 30006.log

    -rw-r--r-- 1 root root    0 5月  31 16:27 appendonly-30001.aof

    -rw-r--r-- 1 root root    0 5月  31 16:20 appendonly-30002.aof

    -rw-r--r-- 1 root root    0 5月  31 16:20 appendonly-30003.aof

    -rw-r--r-- 1 root root    0 5月  31 16:27 appendonly-30004.aof

    -rw-r--r-- 1 root root    0 5月  31 16:27 appendonly-30005.aof

    -rw-r--r-- 1 root root    0 5月  31 16:27 appendonly-30006.aof

    -rwxrwxr-x 1 root root 2321 2月   3 00:39 create-cluster

    -rw-r--r-- 1 root root  175 5月  31 16:27 dump-30001.rdb

    -rw-r--r-- 1 root root  175 5月  31 16:27 dump-30002.rdb

    -rw-r--r-- 1 root root  175 5月  31 16:27 dump-30003.rdb

    -rw-r--r-- 1 root root  175 5月  31 16:27 dump-30004.rdb

    -rw-r--r-- 1 root root  175 5月  31 16:27 dump-30005.rdb

    -rw-r--r-- 1 root root  175 5月  31 16:27 dump-30006.rdb

    -rw-r--r-- 1 root root  787 5月  31 16:27 nodes-30001.conf

    -rw-r--r-- 1 root root  787 5月  31 16:27 nodes-30002.conf

    -rw-r--r-- 1 root root  799 5月  31 16:27 nodes-30003.conf

    -rw-r--r-- 1 root root  799 5月  31 16:27 nodes-30004.conf

    -rw-r--r-- 1 root root  787 5月  31 16:27 nodes-30005.conf

    -rw-r--r-- 1 root root  787 5月  31 16:27 nodes-30006.conf

    -rw-rw-r-- 1 root root 1308 2月   3 00:39 README

 

  四、其餘

    (1) 清除集羣數據,會刪除生成的全部文件,包括aof文件,日誌文件,rdb文件,nodes.conf文件

    cd utils/create-cluster/
    ./create-cluster clean

  

    (2) 中止集羣

    cd utils/create-cluster/
    ./create-cluster stop

  

    (3) create-cluster其餘用法:

    [root@hd4 create-cluster]# create-cluster

    Usage: /usr/bin/create-cluster [start|create|stop|watch|tail|clean]

    start       -- Launch Redis Cluster instances.

    create      -- Create a cluster using redis-trib create.

    stop        -- Stop Redis Cluster instances.

    watch       -- Show CLUSTER NODES output (first 30 lines) of first node.

    tail <id>   -- Run tail -f of instance at base port + ID.

    clean       -- Remove all instances data, logs, configs.

    clean-logs  -- Remove just instances logs.

 

    (4) 解析create-cluster腳本,咱們能夠根據需求修改腳本

    a. PORT=30000 #集羣端口從30000開始,生成「NODES」個實例

    b. TIMEOUT=2000 #指定cluster-node-timeout

    c. NODES=6 #生成節點數量

    d. REPLICAS=1 #表示每一個master須要一個slave

 

玩轉Redis集羣

  現階段Redis集羣的一個問題就是現成的客戶端庫比較少。現知道的有以下幾種:

    ·redis-rb-cluster Ruby實現,是redis-rb的簡單封裝,實現了與集羣交互的基礎功能

    ·redis-py-cluster Python實現的redis-rb-cluster接口,支持大部分redis-py功能,正處於活躍開發狀態

    ·Predis 支持Redis集羣,處於活躍狀態

    ·Jedis java實現,最近添加了對集羣的支持

    ·StackExchange.Redis 提供C#支持(且對大多數.NET語言都適用,VBF#等)

    ·thunk-redis 提供對Node.jsio.js的支持,它是支持pipelining和集羣的thunk/promise-based客戶端

    ·redis-go-cluster 集羣工具,使用Redisgo庫實現的go語言客戶端,經過結果聚合實現MGET/MSET

    ·redis-cli  github中的redis不穩定分支,-c選項提供了基礎的集羣管理功能

 

  如下是redis-cli工具的檢測測試:

    $ redis-cli -c -p 7000

    redis 127.0.0.1:7000> set foo bar

    -> Redirected to slot [12182] located at 127.0.0.1:7002

    OK

    redis 127.0.0.1:7002> set hello world

    -> Redirected to slot [866] located at 127.0.0.1:7000

    OK

    redis 127.0.0.1:7000> get foo

    -> Redirected to slot [12182] located at 127.0.0.1:7002

    "bar"

    redis 127.0.0.1:7000> get hello

    -> Redirected to slot [866] located at 127.0.0.1:7000

    "world"

 

  redis-cli實現了集羣客戶端最基礎的功能:將客戶端請求正確重定向到正確節點。如上例中,寫入和讀取時會自動切換到不一樣節點。邏輯實現比較嚴謹的客戶端能夠緩存哈希槽到節點的映射關係,讓客戶端直接鏈接到正確的節點,只有集羣配置發生改變時才刷新映射關係,如故障轉移後,或者增長/刪除節點。

 

  使用redis-rb-cluster」編寫示例程序

  在說明如何操做Redis集羣前,如故障切換或從新分片,先建立一個示例程序瞭解Redis集羣與客戶端是怎麼交互的。

  咱們經過一個例子,讓部分節點故障或從新分片等,來了解這實際運做中,redis集羣是如何處理的。若是這期間沒有客戶端對集羣發起寫操做,將不益於咱們瞭解狀況

  這節經過2個例子來演示redis-rb-cluster的基礎用法,下面是第一個例子,源碼在redis-rb-cluster目錄下的example.rb文件中。

       1  require './cluster'

       2

       3  if ARGV.length != 2

       4      startup_nodes = [

       5          {:host => "127.0.0.1", :port => 7000},

       6          {:host => "127.0.0.1", :port => 7001}

       7      ]

       8  else

       9      startup_nodes = [

      10          {:host => ARGV[0], :port => ARGV[1].to_i}

      11      ]

      12  end

      13

      14  rc = RedisCluster.new(startup_nodes,32,:timeout => 0.1)

      15

      16  last = false

      17

      18  while not last

      19      begin

      20          last = rc.get("__last__")

      21          last = 0 if !last

      22      rescue => e

      23          puts "error #{e.to_s}"

      24          sleep 1

      25      end

      26  end

      27

      28  ((last.to_i+1)..1000000000).each{|x|

      29      begin

      30          rc.set("foo#{x}",x)

      31          puts rc.get("foo#{x}")

      32          rc.set("__last__",x)

      33      rescue => e

      34          puts "error #{e.to_s}"

      35      end

      36      sleep 0.1

      37  }

 

  程序作的事情很是簡單: 它不斷地以foo<number>爲鍵,number爲值,使用SET命令向數據庫設置鍵值對:

    ·SET foo0 0

    ·SET foo1 1

    ·SET foo2 2

    ·And so forth

 

  代碼中的每一個集羣操做都使用一個beginrescue代碼塊(block)包裹着,由於咱們但願在代碼出錯時,將錯誤打印到終端上面, 而不但願應用由於異常(exception)而退出。

  代碼的第七行是代碼中第一個有趣的地方,它建立了一個Redis集羣對象, 其中建立對象所使用的參數及其意義以下:第一個參數是記錄了啓動節點的startup_nodes列表, 列表中包含了兩個集羣節點的地址。第二個參數指定了對於集羣中的各個不一樣的節點, Redis 集羣對象能夠得到的最大鏈接數,第三個參數timeout指定了一個命令在執行多久以後,纔會被看做是執行失敗。

  啓動列表中並不須要包含全部集羣節點的地址,但這些地址中至少要有一個是有效的:一旦redis-rb-cluster成功鏈接上集羣中的某個節點時,集羣節點列表就會被自動更新, 任何真正的的集羣客戶端都應該這樣作

  如今,程序建立的Redis集羣對象實例被保存到rc變量裏面,咱們能夠將這個對象看成普通Redis對象實例來使用。

  在十一至十九行,咱們先嚐試閱讀計數器中的值,若是計數器不存在的話, 咱們纔將計數器初始化爲0:經過將計數值保存到Redis的計數器裏面,咱們能夠在示例重啓以後,仍然繼續以前的執行過程,而沒必要每次重啓以後都從foo0開始從新設置鍵值對。爲了讓程序在集羣下線的狀況下, 仍然不斷地嘗試讀取計數器的值, 咱們將讀取操做包含在了一個 while 循環裏面, 通常的應用程序並不須要如此當心。

  二十一至三十行是程序的主循環,這個循環負責設置鍵值對,並在設置出錯時打印錯誤信息。程序在主循環的末尾添加了一個sleep調用,讓寫操做的執行速度變慢,幫助執行示例的人更容易看清程序的輸出。執行example.rb程序將產生如下輸出:

  ruby ./example.rb

    1

    2

    3

    4

    5

    6

    7

    8

    9

    ^C (I stopped the program here)

  這個程序並非十分有趣, 稍後咱們就會看到一個更有趣的集羣應用示例, 不過在此以前, 讓咱們先使用這個示例來演示集羣的從新分片操做。

 

集羣從新分片

  現試試對集羣進行從新分片操做。執行從新分片的過程當中,讓example.rb程序處於運行狀態,這樣你就會看到,從新分片並不會對正在運行的集羣程序產生任何影響,你也能夠考慮將example.rb中的sleep調用刪掉,從而讓從新分片操做在近乎真實的寫負載下執行;從新分片操做基本上就是將某些節點上的哈希槽移動到另一些節點上面,和建立集羣同樣,從新分片也可使用redis-trib程序來執行

 

  執行命令可開始一次從新分片操做:

    redis-trib.rb reshard 127.0.0.1:7000

  

  指定集羣中一個節點地址便可,redis-trib」就會自動找到集羣中其餘節點

  目前redis-trib只能在管理員的協助下完成從新分片,要讓redis-trib自動將哈希槽移動到另外一節點目前沒法完成。另外,移動哈希槽目前只能以數量進行移動,不能以百分比進行移動,就是說指定redistrib移動50%哈希槽到另外一節點是不行的,必須指定數字

 

  此命令以問題的方式開啓一次從新分片(reshard)。

  第一個問題,你想從新分片多少個哈希槽:

    >>> Performing Cluster Check (using node 127.0.0.1:7000)

    M: a466e88499423858c5f53de9be640500d9fb3e5b 127.0.0.1:7000

       slots:0-5460 (5461 slots) master

       1 additional replica(s)

    S: b36883be3b39692f71a441a67277ab23dff80afb 127.0.0.1:7004

       slots: (0 slots) slave

       replicates d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f

    M: d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f 127.0.0.1:7002

       slots:10923-16383 (5461 slots) master

       1 additional replica(s)

    S: 9b1d9c3e7bbcc955afce649f439cd2d094957313 127.0.0.1:7003

       slots: (0 slots) slave

       replicates 5055b631a9b310417fa75948a5e473e2e2e1cfee

    M: 5055b631a9b310417fa75948a5e473e2e2e1cfee 127.0.0.1:7001

       slots:5461-10922 (5462 slots) master

      1 additional replica(s)

    S: 406bda57ed591c2bd3b15955f687a57b03a653c0 127.0.0.1:7005

       slots: (0 slots) slave

       replicates a466e88499423858c5f53de9be640500d9fb3e5b

    [OK] All nodes agree about slots configuration.

    >>> Check for open slots...

    >>> Check slots coverage...

    [OK] All 16384 slots covered.

  How many slots do you want to move (from 1 to 16384)? 1000

 

    上面程序一直在運行,此時已經累計很多key了,嘗試移動1000個哈希槽。

 

  此時出現第二個問題,接收這些哈希槽的節點ID是多少:

    What is the receiving node ID?a466e88499423858c5f53de9be640500d9fb3e5b

 

  接下來redis-trib」需知道要把這1000個哈希槽移動到哪一個節點,即哪一個目標節點負責接收這些哈希槽。此時我想移動到127.0.0.1:7000這個節點。指定節點要使用節點ID,且指定的節點必須是master節點信息已經打印在屏幕。也可經過如下命令找到指定節點ID

    redis-cli -p 7000 cluster nodes |grep 127.0.0.1:7000

    a466e88499423858c5f53de9be640500d9fb3e5b 127.0.0.1:7000@17000 myself,master - 0 1528103629000 1 connected 0-5460

 

    可看到目標節點爲:a466e88499423858c5f53de9be640500d9fb3e5b

 

  接下來第三個問題,指定從哪些節點來移動keys到目標節點

    Please enter all the source node IDs.

      Type 'all' to use all the nodes as source nodes for the hash slots. #從其餘每一個master上取一些哈希槽移動到目標節點,選擇「all

      Type 'done' once you entered all the source nodes IDs. #指定要從哪些節點取哈希槽,輸入各節點ID,以回車鍵分隔,完成後輸入「done」指示節點指定完成

      Source node #1:d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f

      Source node #2:5055b631a9b310417fa75948a5e473e2e2e1cfee

      Source node #3:done

 

  接下來會列出要移動的哈希槽信息,而後提示是否執行從新分片計劃:

    Do you want to proceed with the proposed reshard plan (yes/no)?yes

 

    確認後你將看到redis-trib移動的哈希槽的信息,移動的key也會打印出來。

 

  檢查一下哈希槽分佈狀況(平均分佈的時,三個master平均能分配到16384/3個哈希槽):

    redis-trib.rb check 127.0.0.1:7000

    >>> Performing Cluster Check (using node 127.0.0.1:7000)

    M: a466e88499423858c5f53de9be640500d9fb3e5b 127.0.0.1:7000

       slots:0-5961,10923-11421 (6461 slots) master

       1 additional replica(s)

    S: b36883be3b39692f71a441a67277ab23dff80afb 127.0.0.1:7004

       slots: (0 slots) slave

       replicates d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f

    S: 9b1d9c3e7bbcc955afce649f439cd2d094957313 127.0.0.1:7003

       slots: (0 slots) slave

       replicates 5055b631a9b310417fa75948a5e473e2e2e1cfee

    S: 406bda57ed591c2bd3b15955f687a57b03a653c0 127.0.0.1:7005

       slots: (0 slots) slave

       replicates a466e88499423858c5f53de9be640500d9fb3e5b

    M: d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f 127.0.0.1:7002

       slots:11422-16383 (4962 slots) master

       1 additional replica(s)

    M: 5055b631a9b310417fa75948a5e473e2e2e1cfee 127.0.0.1:7001

       slots:5962-10922 (4961 slots) master

       1 additional replica(s)

    [OK] All nodes agree about slots configuration.

    >>> Check for open slots...

    >>> Check slots coverage...

    [OK] All 16384 slots covered.

 

  如何編寫從新分片腳本?

  若是須要常常對集羣執行從新分片,能夠構建一些自動功能,但目前沒法redis-trib自動從新平衡集羣,檢查整個集羣節點上的key分佈、智能地遷移哈希槽,該功能將在將來添加。

  reshard也可不用交互模式執行,如如下命令行:

    redis-trib.rb reshard --from <node-id> --to <node-id> --slots <number of slots> --yes <host>:<port>

 

一個更有趣的程序

  前面使用的示例程序example.rb它只是不斷地對集羣進行寫入,並不檢查寫入結果是否正確。如集羣可能錯誤地將example.rb發送的全部SET命令都改爲了SET foo 42,但因爲example.rb並不檢查寫入後的值,因此它不會意識到集羣實際上寫入的值是錯誤的。所以,redis-rb-cluster 項目包含了一個名爲consistency-test.rb的示例應用,這個應用比起example.rb有趣得多:它建立了多個計數器(默認1000個),並經過發送INCR命令來增長這些計數器的值。

  在增長計數器值的同時,consistency-test.rb還執行如下操做:每次使用INCR命令更新一個計數器時,應用會記錄下計數器執行INCR命令以後應該有的值。好比若是計數器的起始值爲0,而此次是程序第50次向它發送INCR命令,那麼計數器的值應該是50

  在每次發送INCR命令以前,程序會隨機從集羣中讀取一個計數器的值,並將它與本身記錄的值進行對比,看兩個值是否相同。

  也就是說,這個程序是一個一致性檢查器(consistency checker):若集羣在執行INCR命令的過程當中,丟失了某條INCR命令,又或者多執行了某條客戶端沒有確認到的INCR命令,那麼檢查器將察覺到這一點:在前一種狀況中,consistency-test.rb記錄的計數器值將比集羣記錄的計數器值要大;而在後一種狀況中,consistency-test.rb記錄的計數器值將比集羣記錄的計數器值要小。

  運行consistency-test程序將產生相似如下的輸出:

    $ ruby consistency-test.rb

    925 R (0 err) | 925 W (0 err) |

    5030 R (0 err) | 5030 W (0 err) |

    9261 R (0 err) | 9261 W (0 err) |

    13517 R (0 err) | 13517 W (0 err) |

    17780 R (0 err) | 17780 W (0 err) |

    22025 R (0 err) | 22025 W (0 err) |

    25818 R (0 err) | 25818 W (0 err) |

 

    結果展現了執行的讀寫和錯誤(因爲系統不可用而沒有接受的查詢發生的錯誤)的數量.

  若程序察覺了不一致的狀況出現,它將在輸出行的末尾顯式不一致的詳細狀況。好比,若是咱們在consistency-test.rb運行的過程當中,手動修改某個計數器的值:

    $ redis 127.0.0.1:7000> set key_217 0

    OK

 

    (in the other tab I see...)

 

    94774 R (0 err) | 94774 W (0 err) |

    98821 R (0 err) | 98821 W (0 err) |

    102886 R (0 err) | 102886 W (0 err) | 114 lost |

    107046 R (0 err) | 107046 W (0 err) | 114 lost |

    在咱們修改計數器值的時候,計數器的正確值是114(執行了114INCR命令),由於咱們將計數器的值設成了0, 因此consistency-test.rb會向咱們報告說丟失了114INCR命令。

  

  這個程序做爲測試程序頗有意思,因此咱們用這個程序來測試故障恢復

 

  測試故障轉移

  在執行本節操做的過程當中,請一直運行consistency-test程序。要觸發一次故障轉移,最簡單的辦法就是令集羣中的某個master節點進入下線狀態。首先用如下命令列出集羣中的全部master節點:

    redis-cli -p 7000 cluster nodes | grep master

    3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:7001 master - 0 1385482984082 0 connected 5960-10921

    2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 master - 0 1385482983582 0 connected 11423-16383

    97a3a64667477371c4479320d683e4c8db5858b1 :0 myself,master - 0 0 0 connected 0-5959 10922-11422

  經過命令輸出得知端口號爲700070017002的節點都是master節點, 而後咱們能夠經過向端口號7002master節點發送DEBUG SEGFAULT命令,讓這個master節點崩潰:

    redis-cli -p 7002 debug segfault

    Error: Server closed the connection

  如今,切換到運行着consistency-test的標籤頁,能夠看到consistency-test7002下線以後的一段時間裏將產生大量的錯誤警告信息:

 

    18849 R (0 err) | 18849 W (0 err) |

    23151 R (0 err) | 23151 W (0 err) |

    27302 R (0 err) | 27302 W (0 err) |

 

    ... many error warnings here ...

 

    29659 R (578 err) | 29660 W (577 err) |

    33749 R (578 err) | 33750 W (577 err) |

    37918 R (578 err) | 37919 W (577 err) |

    42077 R (578 err) | 42078 W (577 err) |

  從consistency-test的這段輸出能夠看到,集羣在執行故障轉移期間,總共丟失了578個讀命令和577個寫命令,可是並無產生任何數據不一致。這聽上去可能有點奇怪,由於在教程的開頭咱們提到過Redis使用的是異步複製,在執行故障轉移期間,集羣可能會丟失寫命令。可是在實際上,丟失命令的狀況並不常見,由於Redis幾乎是同時執行將命令回覆發送給客戶端,以及將命令複製給slave節點這兩個操做,因此實際上形成命令丟失的時間窗口是很是小的。不過,儘管出現的概率不高,但丟失命令的狀況仍是有可能會出現的,因此咱們對Redis集羣不能提供強一致性的這一描述仍然是正確的。如今, 讓咱們使用cluster nodes命令,查看集羣在執行故障轉移操做以後,主slave節點的佈局狀況:

 

  redis-cli -p 7000 cluster nodes

  3fc783611028b1707fd65345e763befb36454d73 127.0.0.1:7004 slave 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 0 1385503418521 0 connected

  a211e242fc6b22a9427fed61285e85892fa04e08 127.0.0.1:7003 slave 97a3a64667477371c4479320d683e4c8db5858b1 0 1385503419023 0 connected

  97a3a64667477371c4479320d683e4c8db5858b1 :0 myself,master - 0 0 0 connected 0-5959 10922-11422

  3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7005 master - 0 1385503419023 3 connected 11423-16383

  3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:7001 master - 0 1385503417005 0 connected 5960-10921

  2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385503418016 3 connected

 

  如今masters運行在 7000, 7001 7005端口上. 原來的master 7002如今變成了一個7005的一個slave節點.

 

  CLUSTER NODES命令的輸出看起來有點複雜,其實他很是的簡單,含義以下:

    ·節點ID

    ·IP:端口

    ·標誌: master, slave, myself, fail,

    ·若是是個slave節點, 這裏是它的master節點的NODE ID

    ·集羣最近一次向節點發送 PING 命令以後, 過去了多長時間還沒接到回覆。.

    ·節點最近一次返回 PONG 回覆的時間。

    ·節點的配置版本號(configuration epoch):詳細信息請參考Redis集羣規範 。

    ·本節點的網絡鏈接狀況:例如 connected

    ·節點目前包含的槽:例如 127.0.0.1:7001 目前包含號碼爲596010921的哈希槽

 

手動故障轉移

  有時在master沒有任何問題時強制故障轉移是頗有必要的,如想升級masterRedis進程,通常會先故障轉移,將其降級爲slave再進行升級操做,以此下降對整個集羣的影響。

 

  Redis集羣使用「CLUSTER FAILOVER」來手動執行故障轉移,該命令必須在要故障轉移的master的一個slave上執行。

 

  相較於真實的master故障而後故障轉移,手動故障轉移是比較安全的,由於手動故障轉移時客戶端的切換是在確保新的master徹底複製了故障的舊的master數據的前提下發生的,因此避免了數據的丟失

 

  手動執行故障轉移時,slave日誌以下:

    # Manual failover user request accepted.

    # Received replication offset for paused master manual failover: 347540

    # All master replication stream processed, manual failover can start.

    # Start of election delayed for 0 milliseconds (rank #0, offset 347540).

    # Starting a failover election for epoch 7545.

    # Failover election won: I'm the new master.

 

  其基本過程如:客戶端再也不鏈接舊的master,已經鏈接了的會被鎖住,同時舊masterslave發送複製偏移量,slave獲得偏移量後開始故障轉移,而後新master通知舊master更新配置,成爲新masterslave,此時還鏈接在舊master上的客戶端解鎖後會被重定向到新master

 

添加一個新節點

  基本過程是:添加一個空節點,而後移動一些數據給他。有兩種狀況:若新增的是master,從集羣的其餘節點中轉移部分數據給它;若新增的是slave,則告訴它從一個已知的節點中同步複製集。

 

  添加master節點的狀況

    1、添加一個空的redis實例節點,此處添加一個運行在端口7006的實例

    2、將空實例添加到現有集羣中:

    redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000

 

        >>> Send CLUSTER MEET to node 127.0.0.1:7006 to make it join the cluster.

        [OK] New node added correctly.

 

        能夠看到.使用addnode命令來添加節點,第一個參數是新節點的地址,第二個參數是任意一個已經存在的節點的IP和端口

        redis-trib腳本只是給發送「CLUSTER MEET」消息給節點,這也能夠手動地經過客戶端發送,但redis-trib在發送以前會檢查集羣的狀態,因此,仍是用redis-trib腳原本操做集羣會比較好。

  3、查看集羣狀態:

    redis-cli -c -p 7006 cluster nodes

    406bda57ed591c2bd3b15955f687a57b03a653c0 127.0.0.1:7005@17005 slave a466e88499423858c5f53de9be640500d9fb3e5b 0 1528264952479 7 connected

    bde6fc14465ecdbc71c6630edb5f9a3ab0c45cf0 127.0.0.1:7006@17006 myself,master - 0 1528264951000 0 connected

    5055b631a9b310417fa75948a5e473e2e2e1cfee 127.0.0.1:7001@17001 slave 9b1d9c3e7bbcc955afce649f439cd2d094957313 0 1528264951000 8 connected

    9b1d9c3e7bbcc955afce649f439cd2d094957313 127.0.0.1:7003@17003 master - 0 1528264950000 8 connected 5962-10922

    a466e88499423858c5f53de9be640500d9fb3e5b 127.0.0.1:7000@17000 master - 0 1528264951578 7 connected 0-5961 10923-11421

    b36883be3b39692f71a441a67277ab23dff80afb 127.0.0.1:7004@17004 slave d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f 0 1528264952078 3 connected

    d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f 127.0.0.1:7002@17002 master - 0 1528264951477 3 connected 11422-16383

 

    redis-trib.rb check 127.0.0.1:7006

    >>> Performing Cluster Check (using node 127.0.0.1:7006)

    M: bde6fc14465ecdbc71c6630edb5f9a3ab0c45cf0 127.0.0.1:7006

       slots: (0 slots) master

       0 additional replica(s)

    S: 406bda57ed591c2bd3b15955f687a57b03a653c0 127.0.0.1:7005

       slots: (0 slots) slave

       replicates a466e88499423858c5f53de9be640500d9fb3e5b

    S: 5055b631a9b310417fa75948a5e473e2e2e1cfee 127.0.0.1:7001

       slots: (0 slots) slave

       replicates 9b1d9c3e7bbcc955afce649f439cd2d094957313

    M: 9b1d9c3e7bbcc955afce649f439cd2d094957313 127.0.0.1:7003

       slots:5962-10922 (4961 slots) master

       1 additional replica(s)

    M: a466e88499423858c5f53de9be640500d9fb3e5b 127.0.0.1:7000

       slots:0-5961,10923-11421 (6461 slots) master

       1 additional replica(s)

    S: b36883be3b39692f71a441a67277ab23dff80afb 127.0.0.1:7004

       slots: (0 slots) slave

       replicates d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f

    M: d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f 127.0.0.1:7002

       slots:11422-16383 (4962 slots) master

       1 additional replica(s)

    [OK] All nodes agree about slots configuration.

    >>> Check for open slots...

    >>> Check slots coverage...

    [OK] All 16384 slots covered.

 

    與其餘master相比,新節點有兩點區別:

    ·新節點未包含任何數據,由於哈希槽不是自動分配的,須要手工分配到新節點

    ·因爲新節點還未包含哈希槽,當集羣中某個slave想提成爲master時,他不會參與選舉過程

 

  4、從新分配哈希槽,而後檢查哈希槽分佈:

    redis-trib.rb reshard 127.0.0.1:7006

    redis-trib.rb check 127.0.0.1:7006

  

    >>> Performing Cluster Check (using node 127.0.0.1:7006)

    M: bde6fc14465ecdbc71c6630edb5f9a3ab0c45cf0 127.0.0.1:7006

       slots:0-1615,5962-7201,11422-12661 (4096 slots) master

       0 additional replica(s)

    S: 406bda57ed591c2bd3b15955f687a57b03a653c0 127.0.0.1:7005

      slots: (0 slots) slave

       replicates a466e88499423858c5f53de9be640500d9fb3e5b

    S: 5055b631a9b310417fa75948a5e473e2e2e1cfee 127.0.0.1:7001

       slots: (0 slots) slave

       replicates 9b1d9c3e7bbcc955afce649f439cd2d094957313

    M: 9b1d9c3e7bbcc955afce649f439cd2d094957313 127.0.0.1:7003

       slots:1616-1990,7202-10922 (4096 slots) master

       1 additional replica(s)

    M: a466e88499423858c5f53de9be640500d9fb3e5b 127.0.0.1:7000

       slots:2365-5961,10923-11421 (4096 slots) master

       1 additional replica(s)

    S: b36883be3b39692f71a441a67277ab23dff80afb 127.0.0.1:7004

       slots: (0 slots) slave

       replicates d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f

    M: d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f 127.0.0.1:7002

       slots:1991-2364,12662-16383 (4096 slots) master

       1 additional replica(s)

    [OK] All nodes agree about slots configuration.

    >>> Check for open slots...

    >>> Check slots coverage...

    [OK] All 16384 slots covered.

 

  添加slave副本節點的狀況

  添加一個slave副本節點有兩種方法。

  無論使用哪一種方法都得先啓動一個空Redis實例節點

 

  第一種方法:啓動一個Redis空實例,後使用 redis-trib腳本的「--slave」選項

    redis-trib.rb add-node --slave 127.0.0.1:7007 127.0.0.1:7000

      第一個參數是新slave節點的地址;

      第二個參數是任意一個已經存在的節點的IP和端口,不須要指定此slave要添加爲哪一個master副本節點,redis-trib會在擁有最少slave節點的master節點中隨機選一個做爲新增節點的master節點

 

      輸出信息:

          ...

          Automatically selected master 127.0.0.1:7006

          >>> Send CLUSTER MEET to node 127.0.0.1:7007 to make it join the cluster.

          ...

          Configure node as replica of 127.0.0.1:7006.

          ...

 

    也能夠直接指定新增slave節點的master節點:

    redis-trib.rb add-node --slave --master-id a466e88499423858c5f53de9be640500d9fb3e5b 127.0.0.1:7008 127.0.0.1:7003

 

    如此,便指定了新的slave節點是哪一個master節點的副本集。

 

  第二種方法啓動一個Redis空實例,後將新節點以一個空master節點的形式加入到集羣,而後再用「CLUSTER REPLICATE」將其轉換爲slave節點此方法也適用於給從slave節點更換master節點

  如,集羣中master節點127.0.0.1:7002承載的哈希槽範圍是1991-2364,12662-16383,節點IDd1ce7d9db6086c41f13ef0ce3753f82a3bfc420f

    1、將空實例添加到現有集羣中:

      redis-trib.rb add-node 127.0.0.1:7009 127.0.0.1:7000

    二、鏈接空實例,執行復制進程:

      redis-cli -p 7009 CLUSTER REPLICATE d1ce7d9db6086c41f13ef0ce3753f82a3bfc

    三、認證信息:

      redis-cli -p 7000 cluster nodes |grep slave |grep d1ce7d9db6086c41f13ef0ce3753f82a3bfc

      b36883be3b39692f71a441a67277ab23dff80afb 127.0.0.1:7004@17004 slave d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f 0 1528271555000 11 connected

      5837a7c77a04b5100222dca1d226e4980764a97f 127.0.0.1:7009@17009 slave d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f 0 1528271555500 11 connected

 

      可看到127.0.0.1:7004127.0.0.1:7009都是127.0.0.1:7002slave複製節點。

 

刪除節點

  使用del-node」指令刪除slave節點:

    redis-trib.rb del-node 127.0.0.1:7000 `<node-id>`

 

      第一個參數是任意一個節點的地址

      第二個節點是你想要移除的節點ID

 

  使用del-node」指令刪除master節點:

    一、必須先將哈希槽所有遷移至別的master節點

    二、在使用del-node」指令刪除master節點

 

  另外的一個方法是先將master故障轉移降級爲slave,且將另外的slave提高爲master後再刪除節點。顯然,這樣並無減小master節點數量,最終仍是隻能先遷移哈希槽而後執行刪除動做

 

Slave副本節點的遷移(Replicas migration

  Redis集羣中給slaveslave節點更換master節點只需執行指令:

      CLUSTER REPLICATE <master-node-id>

 

  在特定場景下,無需管理員協助,自動將一個slave節點從當前master節點切換到另外一個master節點的自動從新配置過程叫副本遷移(Replicas migration

 

  注意;更多副本遷移的詳細介紹在Redis集羣規範中,此處只作簡單介紹

 

  在某些狀況下,將slave節點遷移到另外一個master節點下的緣由一般是the Redis Cluster is as resistant to failures as the number of replicas attached to a given master

 

  例如若是master節點和slave複製節點同時故障,那麼一個master節點僅有一個slave複製節點的集羣將不能再正常運行,由於沒有其餘Redis實例擁有故障masterslave節點所承載的哈希槽。雖然網絡分區會形成一些節點被隔離,但其餘狀況也會致使集羣故障,如硬件或者軟件的故障致使節點宕機,此狀況通常不會全部節點同時故障。再好比,集羣中每一個master節點都有一個slave節點,凌晨4點時一個slave節點被kill掉,而後master節點在凌晨6點被kill掉,這樣依然會致使集羣不能工做。

 

  爲提升系統可用性,可爲每一個master添加額外的slave複製節點,但會增長成本。副本遷移功能能夠只爲部分master節點增長更多的slave複製節點。如集羣中有10master節點,每一個有一個slave複製節點,共20個實例,而後能夠將一些masterslave增長至3個。

  當集羣中存在一個master節點有多個slave節點,但另外一個master節點沒有slave節點時,複製集遷移功能會在master的多個slave節點中找一個節點,給沒有slave節點的master節點作複製集。如當凌晨4點一個slave節點掛掉,另外一個slave節點將會代替它成爲該master節點的slave節點,而後若是凌晨5master節點掛掉還能有一個slave節點能夠升級爲master,此時集羣仍能夠正常運行。

 

  所以副本遷移功能總結爲:

    ·爲了讓副本遷移功能生效,須要在集羣任意master節點上多添加幾個slave節點

    ·在必要時,集羣找到擁有最多slave節點的master,從其中挑選一個slave,進行副本遷移

    ·redis.conf中「cluster-migration-barrier」參數用於配置副本遷移。此參數保證Redis集羣中不會出現裸奔的master節點,即保證每一個master節點都有slave節點。只有當一個master節點至少擁有給定數量個處於正常工做中的slave節點時,纔會分配slave節點給集羣中孤立的master節點。這個給定數量就是 cluster-migration-barrier。給定數量是1意味着一個slave節點只有在其master節點另外至少還有一個正常工做的slave節點的狀況下才會被分配(副本遷移)。那些分配後仍然剩餘migration barrierslave節點的master節點纔會觸發副本遷移,而不是分配前有migration barrierslave節點的master節點會觸發節點分配!!

 

升級Redis集羣中的節點版本

  升級slave節點版本

  只須要中止slave節點並使用新版本的Redis從新啓動在相同端口便可。在節點關閉期間客戶端鏈接過來會被重定向到另外可用的slave節點上。

 

  升級master節點版本

  相對複雜,建議的流程是:

    一、使用指令CLUSTER FAILOVER」手動觸發故障轉移,使master節點變成slave節點

    二、按照升級slave節點的方式升級該節點

    三、手動觸發故障轉移,讓它變成新的master節點

 

  Redis數據遷移到Redis集羣

  通常,數據遷移發生在兩種狀況下:

    ·原來的數據存在於一個Redis單實例

    ·原來的數據存在於一個分片環境中,數據存儲在多個節點

 

  兩種狀況遷移都很方便,重要的細節是程序是否使用多鍵(multiple keys)操做,以及怎樣使用多鍵操做。有如下三種狀況:

    ·沒有操做多個key(包括操做多個key的指令、事務、lua腳本)。全部key都獨立操做

    ·操做了多個key(包括操做多個key的指令、事務、lua腳本),但這些key都有相同的哈希標籤,好比這些被同時操做的keySUNION{user:1000}.foo {user:1000}.bar

    ·操做了多個key(包括操做多個key的指令、事務、lua腳本),這些key沒有特別處理,也沒有相同標籤。

 

  第三種狀況redis集羣沒法處理,需修改程序:不要使用多個key,或者給這些key加上相同的哈希標籤,而後就能夠遷移啦!

 

  前面兩種狀況能夠直接作遷移,且遷移的流程同樣。

  假設數據現被切割並保存在Nmaster節點存儲(N=1時就是沒有分片的狀況),則須以如下步驟將數據遷移至Redis集羣

    一、中止全部鏈接Redis集羣的客戶端程序。若是有自動在線遷移的方案,也許就不須要中止了。

    二、使用指令BGREWRITEAOF」讓全部master節點產生AOF文件,等待文件建立完成

    三、修改AOF文件名稱爲aof-1, aof-2...aof-N以區別

    四、建立Nmaster節點,且開啓實例的appendonly選項。Slave複製節點可晚些再添加

    五、中止新Redis集羣全部節點,將前面保存的aof-1, aof-2...aof-Naof-1給第一個節點,aof-2給第二個節點,以此類推

    六、重啓全部節點,可能會有警告提示說依據配置部分key不該當存儲在此節點

    七、使用指令redis-trib.rb fix」讓集羣依據哈希槽自動遷移數據

    八、使用指令redis-trib.rb check」檢查集羣狀態是否正常

    九、重啓客戶端程序,檢測數據讀寫

 

  除此以外還可以使用指令redis-trib.rb import」從外部實例中導入數據到redis集羣。該命令將源實例中的數據移動到目標Redis集羣(該指令會把源實例中的數據都刪除)。若源實例版本是Redis2.8,導入過程可能會比較長,由於2.8版本還未實現數據遷移的鏈接緩存,因此建議把源實例Redis版本先升級到3.x,再進行遷移。

相關文章
相關標籤/搜索