在學習Redis Cluster以前,咱們先了解爲何須要集羣,當遇到單機內存、併發、流量等瓶頸時,單機已經沒法知足我讓節點7000和7001等節點進們的要求的時候,能夠採用Cluster架構方案達到負載均衡的目的。node
分佈式數據庫首先要解決把整個數據集按照分區規則映射到多個節點的問題,即把數據集劃分到多個節點上,每一個節點負責總體數據的一個子集。redis
常見的分區規則有哈希分區和順序分區兩種。shell
首先看一下對比數據庫
分佈方式 | 特色 | 典型產品 |
---|---|---|
哈希分區 | 數據分散度高、鍵值分佈無業務無關、沒法順序訪問、支持批量操做。 | 一致性哈希:Mecache、Redis Cluster ... |
順序分區 | 數據分散度易傾斜、鍵值業務相關、能夠順序訪問、支持批量操做。 | BigTable、HBase |
好比:1-100個數字,要保存到3個節點上,每一個節點平均存儲,1-33存儲在第1個節點,34-66存儲到2節點,剩餘存儲到3節點。緩存
順序存儲經常使用在關係型存儲上。架構
由於Redis Cluster採用的哈希分區,因此咱們看一下常見的哈希分區有哪幾種。併發
好比100個數據,對每一個數據進行hash運算以後,再於節點數進行取餘運算,根據餘數保存在不一樣節點上。負載均衡
缺點就是:當節點數量變化時,如擴容或收縮節點,數據節點映射關係須要從新計算,會致使數據的從新遷移。運維
爲系統中每一個節點分配一個token,範圍通常在0~2的32次方,這些token構成一個哈希環。數據讀寫執行節點查找操做時,先根據key計算hash值,而後順時針找到第一個大於等於該哈希值的token節點,以下圖所示異步
這種方式相比節點取餘最大的好處在於加入和刪除節點隻影響哈希環中相鄰的節點,對其餘節點無影響。
但一致性哈希也存在一些問題:
Redis Cluster採用的就是虛擬槽分區。槽的範圍是0~16383,將16384個槽平均分配給節點,由節點進行管理。
每次將key進行hash運算,對16383進行取餘,而後去redis對應的槽進行查找。
槽是集羣內數據管理和遷移的基本單位。採用大範圍槽的主要目的是爲了方便數據拆分和集羣擴展。每一個節點會負責必定數量的槽。
好比咱們如今有5個集羣,每一個節點平均大約負責3276個槽。Redis Cluster 計算公式:slot=CRC16(key)&16383。每個節點負責維護一部分槽以及槽所映射的鍵值數據。
Redis虛擬槽分區的特色:
Redis集羣通常由多個節點組成,節點數量至少爲6個才能保證組成完整高可用的集羣。每一個節點須要開啓配置cluster-enabled yes
,讓Redis運行在集羣模式下。
首先咱們在redis文件中建立三個文件夾:config
、data
、log
。分別存放配置、數據和日誌相關文件。
配置相關redis.conf
#節點端口 port ${port} # 守護進程模式啓動(可選) daemonize yes # 開啓集羣模式 cluster-enabled yes # 節點超時時間,單位毫秒 cluster-node-timeout 15000 # 集羣內部配置文件 cluster-config-file /usr/local/redis/config/nodes-${port}.conf # 節點宕機後是否整個集羣不可用 cluster-require-full-coverage no dir /usr/local/redis/data/ dbfilename dump-${port}.rdb logfile ${port}.log # 其他的配置與redis.conf默認配置文件一致便可
6個節點所有配完成後就能夠開啓了。
[root@localhost config]# ls redis-7000.conf redis-7001.conf redis-7002.conf redis-7003.conf redis-7004.conf redis-7005.conf
[root@localhost redis]# redis-server config/redis-7000.conf [root@localhost redis]# cd config [root@localhost config]# cat nodes-7000.conf f4deba14aac6494e95e3e4ad060c94b8c82df7ec :0 myself,master - 0 0 0 connected vars currentEpoch 0 lastVoteEpoch 0 [root@localhost config]# cd .. [root@localhost redis]# redis-server config/redis-7001.conf [root@localhost redis]# redis-server config/redis-7002.conf [root@localhost redis]# redis-server config/redis-7003.conf [root@localhost redis]# redis-server config/redis-7004.conf [root@localhost redis]# redis-server config/redis-7005.conf [root@localhost redis]# cd config [root@localhost config]# ll 總用量 288 -rw-r--r--. 1 root root 112 12月 17 04:00 nodes-7000.conf -rw-r--r--. 1 root root 112 12月 17 04:00 nodes-7001.conf -rw-r--r--. 1 root root 112 12月 17 04:00 nodes-7002.conf -rw-r--r--. 1 root root 112 12月 17 04:00 nodes-7003.conf -rw-r--r--. 1 root root 112 12月 17 04:00 nodes-7004.conf -rw-r--r--. 1 root root 112 12月 17 04:00 nodes-7005.conf -rw-r--r--. 1 root root 41650 12月 17 03:59 redis-7000.conf -rw-r--r--. 1 root root 41649 12月 17 03:59 redis-7001.conf -rw-r--r--. 1 root root 41651 12月 17 03:59 redis-7002.conf -rw-r--r--. 1 root root 41651 12月 17 03:59 redis-7003.conf -rw-r--r--. 1 root root 41651 12月 17 03:59 redis-7004.conf -rw-r--r--. 1 root root 41651 12月 17 03:59 redis-7005.conf [root@localhost config]# cat nodes-7005.conf d1e8e8e42be8d3b2f3f44d197138e54d91170442 :0 myself,master - 0 0 0 connected vars currentEpoch 0 lastVoteEpoch 0 [root@localhost config]#
檢查節點日誌是否正確:
sudo cat /usr/local/redis/conf/nodes-${port}.conf
文件內容記錄了集羣初始狀態,這裏最重要的是節點ID,它是一個40位16進制字符串,用於惟一標識集羣內一個節點,以後不少集羣操做都要藉助於節點ID來完成。須要注意是,節點ID不一樣於運行ID:節點ID在集羣初始化 時只建立一次,節點重啓時會加載集羣配置文件進行重用,而Redis的運行ID每次重啓都會變化。
咱們如今啓動6個節點,但每一個節點彼此並不知道對方的存在,下面經過節點握手讓6個節點彼此創建聯繫從而組成一個集羣。
[root@localhost redis]# ps -ef |grep redis root 1388 1 0 09:10 ? 00:00:00 redis-server *:7000 [cluster] root 1392 1 0 09:10 ? 00:00:00 redis-server *:7001 [cluster] root 1396 1 0 09:10 ? 00:00:00 redis-server *:7002 [cluster] root 1400 1 0 09:10 ? 00:00:00 redis-server *:7003 [cluster] root 1404 1 0 09:10 ? 00:00:00 redis-server *:7004 [cluster] root 1408 1 0 09:10 ? 00:00:00 redis-server *:7005 [cluster]
節點握手是指一批運行在集羣模式下的節點經過Gossip協議彼此通訊, 達到感知對方的過程
節點握手是集羣彼此通訊的第一步,由客戶端發起下面的命令:
cluster meet {ip} {port}
[root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7001 OK [root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7002 OK [root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7003 OK [root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7004 OK [root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7005 OK [root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7006 OK
上面執行命令以後讓節點7000和7001等節點進行握手通訊。cluster meet
命令是一個異步命令,執行以後馬上返回。內部發起與目標節點進行握手通訊。
這個時候咱們再執行cluster nodes
能夠看到已經檢測到其它節點了。
[root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster nodes d1e8e8e42be8d3b2f3f44d197138e54d91170442 127.0.0.1:7005 master - 0 1609463858135 4 connected 9a8abb84bcc8301a8f11c664471159dc0bf23a62 127.0.0.1:7001 master - 0 1609463860149 1 connected f4deba14aac6494e95e3e4ad060c94b8c82df7ec 127.0.0.1:7000 myself,master - 0 0 0 connected d5f317fc4597dbaac8b26a5897d801a72e45512e 127.0.0.1:7003 master - 0 1609463857127 3 connected 7dbbf232c72405a66416d2a0c335bd072f740644 127.0.0.1:7004 master - 0 1609463859143 5 connected d438b4689776cb6cd6b6d0eaecb7576669c7b3fe 127.0.0.1:7002 master - 0 1609463861156 2 connected
節點創建握手以後集羣還不能正常工做,這時集羣處於下線狀態,全部的數據讀寫都被禁止。經過以下命令能夠看到:
[root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 127.0.0.1:7000> set jack hello (error) CLUSTERDOWN The cluster is down
經過cluster info
命令能夠獲取集羣當前狀態:
127.0.0.1:7000> cluster info cluster_state:fail cluster_slots_assigned:0 cluster_slots_ok:0 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 cluster_size:0 cluster_current_epoch:5 cluster_my_epoch:0 cluster_stats_messages_sent:670 cluster_stats_messages_received:521
能夠看到咱們如今的狀態是fail
,被分配的槽 cluster_slots_assigned
是0,因爲目前全部的槽沒有分配到節點,所以集羣沒法完成槽到節點的映射。只有當16384個槽所有分配給節點後,集羣才進入在線狀態。
Redis集羣把全部的數據映射到16384個槽中。每一個key會映射爲一個固定的槽,只有當節點分配了槽,才能響應和這些槽關聯的鍵命令。經過cluster addslots
命令爲節點分配槽。由於咱們有6個節點,咱們是三主三從的模式,因此只用給三個主節點進行配置便可。
redis-cli -h 127.0.0.1 -p 7000 cluster addslots {0..5461} redis-cli -h 127.0.0.1 -p 7001 cluster addslots {5462..10922} redis-cli -h 127.0.0.1 -p 7002 cluster addslots {10923..16383}
配置成功後,咱們再進入節點看一下:
[root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 127.0.0.1:7000> cluster info cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 cluster_size:3 cluster_current_epoch:5 cluster_my_epoch:0 cluster_stats_messages_sent:1384 cluster_stats_messages_received:1235
能夠看到,cluster_state
和 cluster_slots_assigned
都沒有問題。
目前還有三個節點沒有使用,做爲一個完整的集羣,每一個負責處理槽的節點應該具備從節點,保證當它出現故障時能夠自動進行故障轉移。
集羣模式下,Reids節點角色分爲主節點和從節點。首次啓動的節點和被分配槽的節點都是主節點,從節點負責複製主節點槽信息和相關的數據。使用cluster replicate {node-id}
命令讓一個節點成爲從節點。其中命令執行必須在對應的從節點上執行,node-id是要複製主節點的節點ID。
咱們首先找到三個已經配置槽的節點的node-id。
[root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster nodes d1e8e8e42be8d3b2f3f44d197138e54d91170442 127.0.0.1:7005 master - 0 1609464545892 4 connected 9a8abb84bcc8301a8f11c664471159dc0bf23a62 127.0.0.1:7001 master - 0 1609464547906 1 connected 5462-10922 f4deba14aac6494e95e3e4ad060c94b8c82df7ec 127.0.0.1:7000 myself,master - 0 0 0 connected 0-5461 d5f317fc4597dbaac8b26a5897d801a72e45512e 127.0.0.1:7003 master - 0 1609464546899 3 connected 7dbbf232c72405a66416d2a0c335bd072f740644 127.0.0.1:7004 master - 0 1609464549923 5 connected d438b4689776cb6cd6b6d0eaecb7576669c7b3fe 127.0.0.1:7002 master - 0 1609464548916 2 connected 10923-16383
[root@localhost redis]# redis-cli -h 127.0.0.1 -p 7003 cluster replicate f4deba14aac6494e95e3e4ad060c94b8c82df7ec OK [root@localhost redis]# redis-cli -h 127.0.0.1 -p 7004 cluster replicate 9a8abb84bcc8301a8f11c664471159dc0bf23a62 OK [root@localhost redis]# redis-cli -h 127.0.0.1 -p 7005 cluster replicate d438b4689776cb6cd6b6d0eaecb7576669c7b3fe OK
完成後咱們查看是否已經ok。
[root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster nodes d1e8e8e42be8d3b2f3f44d197138e54d91170442 127.0.0.1:7005 slave d438b4689776cb6cd6b6d0eaecb7576669c7b3fe 0 1609464847442 4 connected 9a8abb84bcc8301a8f11c664471159dc0bf23a62 127.0.0.1:7001 master - 0 1609464846435 1 connected 5462-10922 f4deba14aac6494e95e3e4ad060c94b8c82df7ec 127.0.0.1:7000 myself,master - 0 0 0 connected 0-5461 d5f317fc4597dbaac8b26a5897d801a72e45512e 127.0.0.1:7003 slave f4deba14aac6494e95e3e4ad060c94b8c82df7ec 0 1609464849456 3 connected 7dbbf232c72405a66416d2a0c335bd072f740644 127.0.0.1:7004 slave 9a8abb84bcc8301a8f11c664471159dc0bf23a62 0 1609464848449 5 connected d438b4689776cb6cd6b6d0eaecb7576669c7b3fe 127.0.0.1:7002 master - 0 1609464850468 2 connected 10923-16383
目前爲止,咱們依照Redis協議手動創建一個集羣。它由6個節點構成, 3個主節點負責處理槽和相關數據,3個從節點負責故障轉移。
咱們以前分別使用命令搭建了一個完整的集羣,可是命令過多,當集羣節點衆多時,必然會加大搭建集羣的複雜度和運維成本。所以redis還提供了redis-cli --cluster來搭建集羣。
首先咱們仍是啓動六個單獨的節點。
使用下面命令進行安裝,--cluster-replicas 1
指定集羣中每一個主節點配備幾個從節點,這裏設置爲1。而且該命令會本身建立主節點和分配從節點,其中前3個是主節點,後3個是從節點,後3個從節點分別複製前3個主節點。
redis-cli --cluster create --cluster-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
最後的輸出報告說明:16384個槽所有被分配,集羣建立成功。這裏須要注意命令中節點的地址必須是不包含任何槽/數據的節點,不然會拒絕建立集羣。
若是不想要從節點則不填寫該參數便可--cluster-replicas 1
。
最後咱們可使用下面命令進行查看是否已經ok。
redis-cli --cluster check 127.0.0.1:7000
Redis集羣提供了靈活的節點擴容和收縮方案。在不影響集羣對外服務的狀況下,能夠爲集羣添加節點進行擴容也能夠下線部分節點進行縮容。原理可抽象爲槽和對應數據在不一樣節點之間靈活移動。
當咱們如今有三個節點,此時想增長6385節點,也就是每一個節點把一部分槽和數據遷移到新的節點6385,每一個節點負責的槽和數據相比以前變少了從而達到了集羣擴容的目的。
以前咱們有6個節點,7000~7005節點。
如今咱們增長兩個單獨的節點也就是7006和7007。而後7006節點當作主節點,7007當作從節點。新節點跟集羣內的節點配置保持一致,便於管理統一。
隨後咱們進行啓動
[root@localhost redis]# redis-server config/redis-7006.conf [root@localhost redis]# redis-server config/redis-7007.conf
這個時候咱們的兩個新的節點只是單獨運行,並無加入集羣中。能夠看到下面並無7006和7007節點。
[root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster nodes d1e8e8e42be8d3b2f3f44d197138e54d91170442 127.0.0.1:7005 slave d438b4689776cb6cd6b6d0eaecb7576669c7b3fe 0 1609467765084 4 connected 9a8abb84bcc8301a8f11c664471159dc0bf23a62 127.0.0.1:7001 master - 0 1609467769137 1 connected 5462-10922 f4deba14aac6494e95e3e4ad060c94b8c82df7ec 127.0.0.1:7000 myself,master - 0 0 0 connected 0-5461 d5f317fc4597dbaac8b26a5897d801a72e45512e 127.0.0.1:7003 slave f4deba14aac6494e95e3e4ad060c94b8c82df7ec 0 1609467767119 3 connected 7dbbf232c72405a66416d2a0c335bd072f740644 127.0.0.1:7004 slave 9a8abb84bcc8301a8f11c664471159dc0bf23a62 0 1609467768127 5 connected d438b4689776cb6cd6b6d0eaecb7576669c7b3fe 127.0.0.1:7002 master - 0 1609467766110 2 connected 10923-16383
結構圖以下:
redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7006 redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7007
集羣內新舊節點通過一段時間的ping/pong消息通訊以後,全部節點會發現新節點並將它們的狀態保存到本地。
隨後咱們再進行查看cluster nodes
。
[root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster nodes d1e8e8e42be8d3b2f3f44d197138e54d91170442 127.0.0.1:7005 slave d438b4689776cb6cd6b6d0eaecb7576669c7b3fe 0 1609468208783 4 connected 9a8abb84bcc8301a8f11c664471159dc0bf23a62 127.0.0.1:7001 master - 0 1609468204768 1 connected 5462-10922 f4deba14aac6494e95e3e4ad060c94b8c82df7ec 127.0.0.1:7000 myself,master - 0 0 0 connected 0-5461 d5f317fc4597dbaac8b26a5897d801a72e45512e 127.0.0.1:7003 slave f4deba14aac6494e95e3e4ad060c94b8c82df7ec 0 1609468210798 3 connected 35f9f0abd365bb0fc424dbdaa849f1f1c71163bb 127.0.0.1:7006 master - 0 1609468209790 6 connected 55b028fbd0a0207b6acc6e2b1067bf79f3090534 127.0.0.1:7007 master - 0 1609468206777 7 connected 7dbbf232c72405a66416d2a0c335bd072f740644 127.0.0.1:7004 slave 9a8abb84bcc8301a8f11c664471159dc0bf23a62 0 1609468205773 5 connected d438b4689776cb6cd6b6d0eaecb7576669c7b3fe 127.0.0.1:7002 master - 0 1609468206274 2 connected 10923-16383
而後咱們把7007設置爲7006的從節點
redis-cli -h 127.0.0.1 -p 7007 cluster replicate 35f9f0abd365bb0fc424dbdaa849f1f1c71163bb
再次查看已經OK。
[root@localhost redis]# redis-cli -h 127.0.0.1 -p 7000 cluster nodes d1e8e8e42be8d3b2f3f44d197138e54d91170442 127.0.0.1:7005 slave d438b4689776cb6cd6b6d0eaecb7576669c7b3fe 0 1609470748800 4 connected 9a8abb84bcc8301a8f11c664471159dc0bf23a62 127.0.0.1:7001 master - 0 1609470750824 1 connected 5462-10922 f4deba14aac6494e95e3e4ad060c94b8c82df7ec 127.0.0.1:7000 myself,master - 0 0 0 connected 0-5461 d5f317fc4597dbaac8b26a5897d801a72e45512e 127.0.0.1:7003 slave f4deba14aac6494e95e3e4ad060c94b8c82df7ec 0 1609470745778 3 connected 35f9f0abd365bb0fc424dbdaa849f1f1c71163bb 127.0.0.1:7006 master - 0 1609470746785 6 connected 55b028fbd0a0207b6acc6e2b1067bf79f3090534 127.0.0.1:7007 slave 35f9f0abd365bb0fc424dbdaa849f1f1c71163bb 0 1609470751833 7 connected 7dbbf232c72405a66416d2a0c335bd072f740644 127.0.0.1:7004 slave 9a8abb84bcc8301a8f11c664471159dc0bf23a62 0 1609470749817 5 connected d438b4689776cb6cd6b6d0eaecb7576669c7b3fe 127.0.0.1:7002 master - 0 1609470747795 2 connected 10923-16383
上面咱們添加了兩個新節點:700六、7007。其中7006做爲主節點存儲數據,7007做爲從節點複製7006。下面咱們要把其餘節點的槽和數據遷移到7006這個節點中。
再遷移後原有節點負責的槽數量變爲4096個。
數據遷移過程是逐個槽進行的。流程以下:
cluster setslot {slot} importing {sourceNodeId}
命令,讓目標節點準備導入槽數據。cluster setslot {slot} migrating {targetNodeId}
命令,讓源節點準備遷出槽數據。cluster getkeysinslot {slot} {count}
命令,每次獲取count個屬於槽的鍵。migrate {targetIP} {targetPort} key 0 {timeout}
命令,把指定的key遷移。cluster setslot {slot} node {targetNodeId}
命令,通知槽分配給目標節點。僞代碼以下:
def move_slot(source,target,slot): # 目標節點準備導入槽 target.cluster("setslot",slot,"importing",source.nodeId); # 源節點準備全出槽 source.cluster("setslot",slot,"migrating",target.nodeId); while true : # 批量從源節點獲取鍵 keys = source.cluster("getkeysinslot",slot,pipeline_size); if keys.length == 0: # 鍵列表爲空時,退出循環 break; # 批量遷移鍵到目標節點 source.call("migrate",target.host,target.port,"",0,timeout,"keys",keys); # 向集羣全部主節點通知槽被分配給目標節點 for node in nodes: if node.flag == "slave": continue; node.cluster("setslot",slot,"node",target.nodeId);
redis-cli --cluster reshard host:port --from <arg> --to <arg> --slots <arg> --yes --timeout <arg> --pipeline <arg>
host
:port:必傳參數,集羣內任意節點地址,用來獲取整個集羣信息。--from
:制定源節點的id,若是有多個源節點,使用逗號分隔,若是是all源節點變爲集羣內全部主節點,在遷移過程當中提示用戶輸入。--to
:須要遷移的目標節點的id,目標節點只能填寫一個,在遷移過程 中提示用戶輸入。--slots
:須要遷移槽的總數量,在遷移過程當中提示用戶輸入。--yes
:當打印出reshard執行計劃時,是否須要用戶輸入yes確認後再執行reshard。--timeout
:控制每次migrate操做的超時時間,默認爲60000毫秒。·--pipeline
:控制每次批量遷移鍵的數量,默認爲10。開始遷移:
redis-cli --cluster reshard 127.0.0.1:7000
輸入須要遷移的槽數量,此處咱們輸入4096。
目標節點ID,只能指定一個,由於咱們須要遷移到7006中,所以下面輸入7006的ID。
以後輸入源節點的ID,redis會從這些源節點中平均取出對應數量的槽,而後遷移到6385中,下面咱們分別輸入7000、700一、7002的節點ID。最後要輸入done
表示結束。
最後輸入yes便可。
咱們能夠檢查一下節點之間的平衡性
redis-cli --cluster rebalance 127.0.0.1:6380
全部主節點負責的槽數量差別在2%之內,就算集羣節點數據相對均勻,無需調整。
收縮正好和擴容遷移方向相反,7006變爲源節點,其餘主節點變爲目標節點,源節點須要把自身負責的4096個槽均勻地遷移到其餘主節點上。
具體步驟和上述擴容相似,這裏就不演示。
在集羣模式下,Redis接收任何鍵相關命令時首先計算鍵對應的槽,再根據槽找出所對應的節點,若是節點是自身,則處理鍵命令;不然回覆MOVED重定向錯誤,通知客戶端請求正確的節點。
由於咱們執行cluster keyslot hello
以後,發現槽的位置在866,在咱們之中,因此直接返回。
127.0.0.1:7000> set hello world OK 127.0.0.1:7000> cluster keyslot hello (integer) 866 127.0.0.1:7000> get hello "world"
因爲鍵對應槽是6918,不屬於7000節點,則回覆MOVED {slot} {ip} {port}格式重定向信息:
127.0.0.1:7000> set test hello (error) MOVED 6918 127.0.0.1:7001
咱們能夠切換到7001發送命令便可成功。
127.0.0.1:7001> set test hello OK
用redis-cli命令時,能夠加入-c參數支持自動重定向,簡化手動發起重定向操做。
[root@localhost config]# redis-cli -h 127.0.0.1 -p 7000 -c 127.0.0.1:7000> set test hello -> Redirected to slot [6918] located at 127.0.0.1:7001 OK
Redis集羣支持在線遷移槽(slot)和數據來完成水平伸縮,當slot對應的數據從源節點到目標節點遷移過程當中,客戶端須要作到智能識別,保證鍵命令可正常執行。例如當一個slot數據從源節點遷移到目標節點時,期間可能出現一部分數據在源節點,而另外一部分在目標節點。
當出現上述狀況時,客戶端鍵命令執行流程將發生變化,以下所示:
(error) ASK {slot} {targetIP}:{targetPort}
。asking
命令到目標節點打開客戶端鏈接標識,再執行鍵命令。若是存在則執行,不存在則返回不存在信息。所以故障發現也是經過消息傳播機制實現的,主要環節包括:
集羣中每一個節點都會按期向其餘節點發送ping消息,接收節點回復pong消息做爲響應。若是在cluster-node-timeout時間內通訊一直失敗,則發送節點會認爲接收節點存在故障,把接收節點標記爲主觀下線(pfail)狀態。
主觀下線流程:
cluster-nodetimeout
時,更新本地對節點b的狀態爲主觀下線(pfail)。當半數以上持有槽的主節點都標記某節點主觀下線。
客觀下線流程:
故障節點變爲客觀下線後,若是下線節點是持有槽的主節點則須要在它的從節點中選出一個替換它,從而保證集羣的高可用。下線主節點的全部從節點承擔故障恢復的義務,當從節點經過內部定時任務發現自身複製的主節點進入客觀下線時,將會觸發故障恢復流程。
cluster-node-timeout * cluster-slave-validity-factor
,則當前從節點不具有故障轉移資格。參數cluster-slavevalidity-factor
用於從節點的有效因子,默認爲10。當從節點符合故障轉移資格後,更新觸發故障選舉的時間,只有到達該時間後才能執行後續流程。
主節點b進入客觀下線後,它的三個從節點根據自身複製偏移量設置延遲選舉時間,如複製偏移量最大的節點slave b-1延遲1秒執行,保證複製延遲低的從節點優先發起選舉。
當從節點收集到足夠的選票以後,觸發替換主節點操做:
clusterDelSlot
操做撤銷故障主節點負責的槽,並執行clusterAddSlot
把這些槽委派給本身。