首頁 > 軟體

比較幾種Redis叢集方案

2021-06-21 13:01:56

一、概述

在Redis3.0以前的叢集一般是藉助哨兵sentinel工具來監控主節點的狀態,如果主節點異常,則會做主從切換,將某一臺slave作為master。哨兵的設定略微複雜,並且效能和高可用性等各方面表現一般,特別是在主從切換的瞬間存在存取瞬斷的情況,叢集會需要十幾秒甚至幾十秒的時間用於判斷主節點下線,並選舉一個從節點成為新的主節點。在某寶雙11這樣高並行的場景如果出現Redis主節點存取瞬斷是一件非常可怕的事,這意味著幾千萬的商品、訂單查詢請求將直接請求資料庫,資料庫很可能因為大批次的查詢請求而崩潰。

哨兵模式通常只有一個主節點對外提供服務,沒法支援很高的並行,假設一個Redis節點允許支援10W的並行,但面對雙11幾千萬的並行量還是捉襟見肘的,且單個主節點記憶體也不宜設定得過大,否則會導致持久化檔案過大,影響資料恢復或主從同步的效率。

哨兵模式

Redis叢集的效能和高可用性均優於之前版本的哨兵模式,且叢集設定簡單。高可用叢集相較於哨兵叢集,至少不會出現主節點下線後,整個叢集在一段時間內處於不可用狀態,直到選舉出主節點。因為高可用叢集有多個主節點,當我們需要向整個Redis服務寫入大批次資料時,資料會根據寫入的key算出一個hash值,將資料落地到不同的主節點上,所以當一個主節點下線後,落地到其他主節點的寫請求還是正常的。

高可用叢集模式

二、Redis高可用叢集搭建

Redis叢集需要至少三個主節點,我們這裡搭建三個主節點,並且給每個主節點再搭建一個從節點,總共6個Redis節點,埠號從8001~8006,這裡筆者依舊是在一臺機器上部署六個節點,搭建步驟如下:

設定1-1

#在Redis安裝目錄下建立一個config和data目錄,並將redis.conf檔案拷貝到config目錄下並更名為redis-8001.conf進行設定修改。有部分設定再之前的主從&哨兵叢集有講解過,這裡便不再贅述。

port 8001

protected-mode no

daemonize yes

pidfile "/var/run/redis-8001.pid"

logfile "8001.log"

dir "/home/lf/redis-6.2.1/data"

dbfilename "dump-8001.rdb"

#bind 127.0.0.1 -::1

appendonly yes

appendfilename "appendonly-8001.aof"

requirepass "123456"

#設定叢集存取密碼

masterauth 123456

#啟動叢集模式

cluster-enabled yes

#叢集節點資訊檔案,這裡800x最好和port對應上

cluster-config-file nodes-8001.conf

#設定節點超時時間,單位:毫秒

cluster-node-timeout 15000

修改完畢redis-8001.conf設定後,我們複製該設定並更名為redis-8002.conf、redis-8003.conf、redis-8004.conf、redis-8005.conf、redis-8006.conf,然後我們將檔案裡的8001分別替換成8002、8003、8004、8005、8006,可以批次替換:

:%s/源字串/目的字串/g

注意,如果叢集是搭建在不同的伺服器上,大家還要在每臺伺服器上執行下面的命令關閉下防火牆,避免出現因為防火牆導致不同伺服器的Redis程序無法互相存取:

systemctl stop firewalld # 臨時關閉防火牆

systemctl disable firewalld # 禁止開機啟動

之後,我們單獨修改redis-8001.conf的設定:

min-replicas-to-write 1

這個設定可以讓我們在向主節點寫資料時,主節點必須至少同步到一個從節點才會返回,如果配3則主節點必須同步到3個節點才會返回,這個設定可以在主節點下線,從節點切換為主節點時減少資料的丟失,但這個設定也不能完全規避在主節點下線時資料的丟失,並且存在效能的損耗,因為主節點必須確認資料同步到一定量的從節點,才能將使用者端的請求返回。

現在,我們依次啟動埠為8001~8006的Redis服務:

[root@master redis-6.2.1]# src/redis-server config/redis-8001.conf

[root@master redis-6.2.1]# src/redis-server config/redis-8002.conf

[root@master redis-6.2.1]# src/redis-server config/redis-8003.conf

[root@master redis-6.2.1]# src/redis-server config/redis-8004.conf

[root@master redis-6.2.1]# src/redis-server config/redis-8005.conf

[root@master redis-6.2.1]# src/redis-server config/redis-8006.conf

之前建立的6個Redis服務還是獨立的服務,下面我們來看下將這6個服務組成一個叢集的命令:

[root@master redis-6.2.1]# src/redis-cli --cluster help

Cluster Manager Commands:

  create         host1:port1 ... hostN:portN #組成叢集的Redis服務的IP和埠

                 --cluster-replicas <arg> #叢集副本數量,填N代表每個主節點有N個從節點<br>……

現在,我們按照上面的命令將6個Redis服務組成一個叢集,我們有6個Redis服務,所以會有3個主節點,3個從節點,--cluster-replicas的引數我們應該填1:

#建立叢集

[root@master redis-6.2.1]# src/redis-cli -a 123456 --cluster create --cluster-replicas 1 192.168.6.86:8001 192.168.6.86:8002 192.168.6.86:8003 192.168.6.86:8004 192.168.6.86:8005 192.168.6.86:8006

>>> Performing hash slots allocation on 6 nodes...

Master[0] -> Slots 0 - 5460

Master[1] -> Slots 5461 - 10922

Master[2] -> Slots 10923 - 16383

Adding replica 192.168.6.86:8005 to 192.168.6.86:8001

Adding replica 192.168.6.86:8006 to 192.168.6.86:8002

Adding replica 192.168.6.86:8004 to 192.168.6.86:8003

>>> Trying to optimize slaves allocation for anti-affinity

[WARNING] Some slaves are in the same host as their master

#<1>

M: 28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001

   slots:[0-5460] (5461 slots) master

M: baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002

   slots:[5461-10922] (5462 slots) master

M: 115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003

   slots:[10923-16383] (5461 slots) master

S: 54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004

   replicates baf630fe745d9f1db7a58ffb96e180fab1047c79

S: 9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005

   replicates 115a626ee6d475076b096181ab10d3ab6988cc04

S: aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006

   replicates 28ad6b59866832b13dbd58dd944e641862702e23

Can I set the above configuration? (type 'yes' to accept): yes #<2>

>>> Nodes configuration updated

>>> Assign a different config epoch to each node

>>> Sending CLUSTER MEET messages to join the cluster

Waiting for the cluster to join

>>> Performing Cluster Check (using node 192.168.6.86:8001)

#<3>

M: 28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001

   slots:[0-5460] (5461 slots) master

   1 additional replica(s)

S: aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006

   slots: (0 slots) slave

   replicates 28ad6b59866832b13dbd58dd944e641862702e23

M: baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002

   slots:[5461-10922] (5462 slots) master

   1 additional replica(s)

S: 9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005

   slots: (0 slots) slave

   replicates 115a626ee6d475076b096181ab10d3ab6988cc04

M: 115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003

   slots:[10923-16383] (5461 slots) master

   1 additional replica(s)

S: 54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004

   slots: (0 slots) slave

   replicates baf630fe745d9f1db7a58ffb96e180fab1047c79

[OK] All nodes agree about slots configuration.

>>> Check for open slots...

>>> Check slots coverage...

[OK] All 16384 slots covered.

我們節選建立叢集的部分返回來解析,下面有3個M和3個S,分別代表主節點master和從節點slave,之後是節點的ID、IP+埠,叢集預設會使用我們輸入的前三個服務作為主節點,根據我們之前輸入的引數,埠號8001、8002、8003的服務作為主節點。主節點還會有該節點所對應的槽位,Redis會將資料劃分為16384個槽位(slots),每個節點負責儲存一部分槽位,比如8001對應的槽位是[0,5460],8002對應的槽位是[5461,10922],8003對應的槽位是[10923,16383],當我們要儲存或讀取一個key值時,Redis使用者端會根據key的hash值去對應槽位的主節點執行命令。我們再來看下從節點,從節點的格式大部分和主節點類似,除了槽位那部分,從節點可以根據replicates {masterID}查詢該節點對應的主節點ID,比如8004從節點對應主8002主節點,8005從節點對應8003主節點,8006從節點對應主節點8001。

#<1>

M(主節點): 28ad6b59866832b13dbd58dd944e641862702e23(節點ID) 192.168.6.86:8001(節點的IP和埠)

   slots:[0-5460] (5461 slots) master(節點槽位,key的hash值在0~5460會落地到該節點)

M: baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002

   slots:[5461-10922] (5462 slots) master

M: 115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003

   slots:[10923-16383] (5461 slots) master

S: 54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004

   replicates baf630fe745d9f1db7a58ffb96e180fab1047c79

S: 9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005

   replicates 115a626ee6d475076b096181ab10d3ab6988cc04

S(從節點): aa6ce37e876660161403a801adb8fc7a79a9d876(節點ID) 192.168.6.86:8006(節點的IP和埠)

   replicates 28ad6b59866832b13dbd58dd944e641862702e23(該從節點對應主節點的ID)

如果同意Redis叢集的主從劃分,則在<2>處輸入yes並回車。<3>處則是真實劃分,如果沒有意外內容應該跟<1>處大致類似。之前,我們把所有的節點都搭建在一臺伺服器上,如果我們把節點部署在多臺伺服器上,那麼Redis在劃分主從時,會刻意將主從節點劃分到不同的伺服器上,這是因為Redis期望如果一臺伺服器掛了,不會導致一整個主從叢集都不可用,將主從劃分到不同機器上,可以保證如果主節點所在的伺服器掛了,從節點能切換成主節點。

如果我們想檢視叢集資訊,可以連線到任意一個節點,執行CLUSTER NODES或者CLUSTER INFO命令:

[root@master redis-6.2.1]# src/redis-cli -a 123456 -c -p 8001

127.0.0.1:8001> CLUSTER NODES

aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006@18006 slave 28ad6b59866832b13dbd58dd944e641862702e23 0 1618317182151 1 connected

baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002@18002 master - 0 1618317187163 2 connected 5461-10922

9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005@18005 slave 115a626ee6d475076b096181ab10d3ab6988cc04 0 1618317186161 3 connected

115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003@18003 master - 0 1618317184000 3 connected 10923-16383

54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004@18004 slave baf630fe745d9f1db7a58ffb96e180fab1047c79 0 1618317186000 2 connected

28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001@18001 myself,master - 0 1618317184000 1 connected 0-5460

127.0.0.1:8001> 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:6

cluster_my_epoch:1

cluster_stats_messages_ping_sent:61

cluster_stats_messages_pong_sent:62

cluster_stats_messages_sent:123

cluster_stats_messages_ping_received:57

cluster_stats_messages_pong_received:61

cluster_stats_messages_meet_received:5

cluster_stats_messages_received:123

執行CLUSTER NODES可以看到叢集的主從劃分,主節點所管理的槽位,從節點對接的主節點,以及各個節點的連線數。這裡要注意一點,如果叢集所有的伺服器都崩潰了,待伺服器啟動時如果我們想重啟整個叢集,不需要再用redus-cli --cluster create命令去建立叢集,只要啟動每個8001~8006的Redis節點,整個叢集便會恢復,因為叢集一旦建立成功,叢集的節點資訊會被寫入之前設定的nodes-800X.conf檔案中。

現在我們來測試叢集,我們分別設定兩個鍵值對<python,flask>、<java,spring>:

[root@master redis-6.2.1]# src/redis-cli -a 123456 -c -p 8001

127.0.0.1:8001> SET python flask

-> Redirected to slot [7252] located at 192.168.6.86:8002

OK

192.168.6.86:8002> SET java spring

-> Redirected to slot [858] located at 192.168.6.86:8001

OK

192.168.6.86:8001> GET java

"spring"

192.168.6.86:8001> GET python

-> Redirected to slot [7252] located at 192.168.6.86:8002

"flask"

根據上面的輸出結果我們可以看到,在設定<python,flask>鍵值對時,Redis計算出python對應的hash值為7252,處於8002節點所管轄的槽位[5461-10922],會幫我們重定向到8002節點。當我們在8002主節點設定<java,spring>,Redis服務算出java對應的hash值為858,處於8001節點所管轄的槽位[0-5460],又會幫我們重定向到8001.同理執行GET命令時也會幫助我們重定向。

現在,我們再來殺死8001的從節點8006程序,測試之前單獨設定給8001的min-replicas-to-write是否能生效,之前我們設定8001必須將寫入的資料同步到至少一個從節點才能返回,現在我們再往埠8001的Redis服務設定<java,tomcat>鍵值對:

[root@master redis-6.2.1]# ps -ef | grep redis

root      44661  22426  0 19:50 pts/0    00:00:00 grep --color=auto redis

root     108814      1  0 Apr13 ?        00:13:24 src/redis-server *:8002 [cluster]

root     108820      1  0 Apr13 ?        00:13:31 src/redis-server *:8003 [cluster]

root     108826      1  0 Apr13 ?        00:13:14 src/redis-server *:8004 [cluster]

root     108835      1  0 Apr13 ?        00:13:43 src/redis-server *:8005 [cluster]

root     108923      1  0 Apr13 ?        00:13:21 src/redis-server *:8001 [cluster]

root     109206      1  0 Apr13 ?        00:13:28 src/redis-server *:8006 [cluster]

root     109315      1  0 Apr13 ?        00:13:43 src/redis-server *:8007 [cluster]

root     109324      1  0 Apr13 ?        00:13:20 src/redis-server *:8008 [cluster]

root     109963 103945  0 Apr13 pts/1    00:00:00 src/redis-cli -a 123456 -c -p 8001

#殺死8006埠的Redis服務

[root@master redis-6.2.1]# kill -9 109206

#連線到8001Redis服務後,嘗試設定<java,tomcat>鍵值對,可以看到報錯:沒有足夠的從節點寫入。

192.168.6.86:8001> SET java tomcat

(error) NOREPLICAS Not enough good replicas to write.

從上面的的結果我們可以確定,min-replicas-to-write N確實可以保證在向Redis主節點寫入資料時至少同步到N個從節點後才會返回,如果我們重啟8006從節點,8006節點會自動重新加入叢集,於是8001主節點又可以正常設定鍵值對:

[root@master redis-6.2.1]# src/redis-server config/redis-8006.conf

192.168.6.86:8001> SET java tomcat

OK

三、Redis叢集節點間的通訊機制

Redis Cluster節點間採取gossip協定進行通訊,維護叢集的後設資料(叢集節點資訊,主從角色,節點數量,各節點共用的資料等)有兩種方式:集中式和gossip

3.1、集中式

優點在於後設資料的更新和讀取具有良好的時效性,一旦後設資料出現變更立即就會更新到集中式的儲存中,其他節點讀取的時候可以立即感知到;不足的是所有後設資料的更新壓力全部集中在一個地方,可能導致後設資料的儲存壓力。很多中介軟體都會藉助zookeeper集中式儲存後設資料。

3.2、gossip

gossip協定包含多種訊息,包括ping,pong,meet,fail等等。

  • meet:某個節點傳送meet給新加入的節點,讓新節點加入叢集中,然後新節點就會開始與其他節點進行通訊。
  • ping:每個節點都會頻繁給其他節點傳送ping,其中包含自己的狀態還有自己維護的叢集後設資料,互相通過ping交換後設資料(類似自己感知到的叢集節點增加和移除,hash slot資訊等);
  • pong: 對ping和meet訊息的返回,包含自己的狀態和其他資訊,也可以用於資訊廣播和更新;
  • fail:某個節點判斷另一個節點下線後,就傳送fail給其他節點,通知其他節點指定的節點宕機了。

gossip協定的優點在於後設資料的更新比較分散,不是集中在一個地方,更新請求會陸陸續續傳輸到所有節點上,降低了壓力,但存在一定的延時,可能導致叢集的一些操作存在滯後。每個節點都有一個專門用於節點間gossip通訊的埠,就是自己提供服務的埠號+10000,比如8001,那麼用於節點間通訊的埠就是18001埠。每個節點每隔一段時間都會往另外幾個節點傳送ping訊息,同時其他幾點接收到ping訊息之後返回pong訊息。

四、網路抖動

線上的機房網路往往並不總是風平浪靜的,經常會發生各種各樣的問題。比如網路抖動就是很常見的現象,突然間部分連線變得不可存取,過段時間又恢復正常了。

為解決這種問題,Redis Cluster提供了一個選項cluster--node--timeout,表示當某個節點持續timeout的時間失聯時,才可以判定該節點出現故障,需要進行主從切換。如果沒有這個選項,網路抖動會導致主從頻繁切換 (資料的重新複製)。

五、Redis叢集選舉原理分析

當從節點發現自己的主節點變為fail狀態時,便嘗試進行failover,以期成為新的主節點。由於掛掉的主節點可能會有多個從節點,從而存在多個從節點競爭成為主節點的過程,其過程如下:

1.從節點發現自己的主節點變為fail。

2.將自己記錄的叢集currentEpoch加1,並廣播FAILOVER_AUTH_REQUEST資訊。

3.其他節點收到該資訊,只有主節點響應,判斷請求者的合法性,並行送FAILOVER_AUTH_ACK,對每一個epoch只傳送一次ack。

4.嘗試failover的從節點收集其他主節點返回的FAILOVER_AUTH_ACK。

5.從節點收到超過半數主節點的ack後變成新主節點(這裡解釋了叢集為什麼至少需要三個主節點,如果只有兩個,當其中一個掛了,只剩一個主節點是不能選舉成功的)

6.從節點廣播pong訊息通知其他叢集節點,從節點並不是在主節點一進入fail狀態就馬上嘗試發起選舉,而是有一定延遲,一定的延遲確保我們等待fail狀態在叢集中傳播,從節點如果立即嘗試選舉,其它主節點尚未意識到fail狀態,可能會拒絕投票。

延遲計算公式:DELAY = 500ms + random(0~500ms)+SALVE_RANK*1000ms
SALVE_RANK表示此從節點從主節點複製資料的總量的rank。rank越小代表已複製的資料越新。這種方式下,持有最新資料的從節點將會首先發起選舉。

5.1、叢集是否完整才能對外提供服務

當redis.conf的設定cluster-require-full-coverage為no時,表示當負責一個主庫下線且沒有相應的從庫進行故障恢復時,叢集仍然可用,如果為yes則叢集不可用。

5.2、Redis叢集為什麼至少需要三個master節點,並且推薦節點數為奇數?

對於類似MSET,MGET這樣可以操作多個key的命令,Redis叢集只支援所有key落在同一slot的情況,如果有多個key一定要用類似MSET命令在Redis叢集上批次操作,則可以在key的前面加上{XX},這樣資料分片hash計算的只會是大括號裡的值,可以確保不同的key能落到同一slot裡去,範例如下:

#user:1:name和user:2:name兩個key會落地到不同的槽位,所以不能用類似MSET批次操作key的命令

192.168.6.86:8002> MSET user:1:name Tom user:2:name Amy

(error) CROSSSLOT Keys in request don't hash to the same slot

#如果用{XX}字首,可以保證{user}:1:name和{user}:2:name落地到同一個槽位

192.168.6.86:8002> MSET {user}:1:name Tom {user}:2:name Amy

-> Redirected to slot [5474] located at 192.168.6.86:8001

OK

192.168.6.86:8001> MGET {user}:1:name {user}:2:name

1) "Tom"

2) "Amy"

5.3、哨兵leader選舉流程

當一個主節點伺服器被某哨兵視為下線狀態後,該哨兵會與其他哨兵協商選出哨兵的leader進行故障轉移工作。每個發現主節點下線的哨兵都可以要求其他哨兵選自己為哨兵的leader,選舉是先到先得。每個哨兵每次選舉都會自增選舉週期,每個週期中只會選擇一個哨兵作為的leader。如果所有超過一半的哨兵選舉某哨兵作為leader。之後該哨兵進行故障轉移操作,在存活的從節點中選舉出新的主節點,這個選舉過程跟叢集的主節點選舉很類似。

哨兵叢集哪怕只有一個哨兵節點,在主節點下線時也能正常選舉出新的主節點,當然那唯一一個哨兵節點就作為leader選舉新的主節點。不過為了高可用一般都推薦至少部署三個哨兵節點。為什麼推薦奇數個哨兵節點原理跟叢集奇數個主節點類似。

六、新增/刪除節點

到此為止,我們學習瞭如何建立叢集、如何向叢集設定鍵值對,我們還差瞭解如何往叢集里加入節點和刪除節點。這裡筆者會帶大家一起往叢集加入一對8007和8008埠的Redis主從節點,然後再將這對主從從叢集裡移除。我們按照之前的步驟複製redis.conf到config目錄下,更名為redis-8007.conf和redis-8008.conf,並按照設定1-1將原先8001替換成8007和8008,然後啟動8007和8008兩個Redis服務:

[root@master redis-6.2.1]# src/redis-server config/redis-8007.conf

[root@master redis-6.2.1]# src/redis-server config/redis-8008.conf

然後我們執行redis-cli --cluster help檢視如何將新節點加入叢集:

[root@master redis-6.2.1]# src/redis-cli --cluster help

Cluster Manager Commands:

  create         host1:port1 ... hostN:portN

                 --cluster-replicas <arg>

  check          host:port

                 --cluster-search-multiple-owners

  info           host:port

  fix            host:port

                 --cluster-search-multiple-owners

                 --cluster-fix-with-unreachable-masters

  reshard        host:port

                 --cluster-from <arg>

                 --cluster-to <arg>

                 --cluster-slots <arg>

                 --cluster-yes

                 --cluster-timeout <arg>

                 --cluster-pipeline <arg>

                 --cluster-replace

  rebalance      host:port

                 --cluster-weight <node1=w1...nodeN=wN>

                 --cluster-use-empty-masters

                 --cluster-timeout <arg>

                 --cluster-simulate

                 --cluster-pipeline <arg>

                 --cluster-threshold <arg>

                 --cluster-replace

  add-node       new_host:new_port existing_host:existing_port

                 --cluster-slave

                 --cluster-master-id <arg>

  del-node       host:port node_id

  call           host:port command arg arg .. arg

                 --cluster-only-masters

                 --cluster-only-replicas

  set-timeout    host:port milliseconds

  import         host:port

                 --cluster-from <arg>

                 --cluster-from-user <arg>

                 --cluster-from-pass <arg>

                 --cluster-from-askpass

                 --cluster-copy

                 --cluster-replace

  backup         host:port backup_directory

  help          

1.create:建立一個叢集環境host1:port1 ... hostN:portN。

2.call:可以執行redis命令。

3.add-node:將一個節點新增到叢集裡,第一個引數為新節點的ip:port,第二個引數為叢集中任意一個已經存在的節點的ip:port。

4.del-node:移除一個節點。

5.reshard:重新分片。

6.check:檢查叢集狀態。

現在,我們將8007Redis服務加入到叢集,這裡需要我們填入兩個引數,一個是新加入的節點IP和埠,一個是已存在在叢集的IP和埠,分別是192.168.6.86:8007和192.168.6.86:8001:

[root@master redis-6.2.1]# src/redis-cli -a 123456 --cluster add-node 192.168.6.86:8007 192.168.6.86:8001

Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.

>>> Adding node 192.168.6.86:8007 to cluster 192.168.6.86:8001

>>> Performing Cluster Check (using node 192.168.6.86:8001)

M: 28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001

   slots:[0-5460] (5461 slots) master

   1 additional replica(s)

S: aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006

   slots: (0 slots) slave

   replicates 28ad6b59866832b13dbd58dd944e641862702e23

M: baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002

   slots:[5461-10922] (5462 slots) master

   1 additional replica(s)

S: 9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005

   slots: (0 slots) slave

   replicates 115a626ee6d475076b096181ab10d3ab6988cc04

M: 115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003

   slots:[10923-16383] (5461 slots) master

   1 additional replica(s)

S: 54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004

   slots: (0 slots) slave

   replicates baf630fe745d9f1db7a58ffb96e180fab1047c79

[OK] All nodes agree about slots configuration.

>>> Check for open slots...

>>> Check slots coverage...

[OK] All 16384 slots covered.

>>> Send CLUSTER MEET to node 192.168.6.86:8007 to make it join the cluster.

[OK] New node added correctly.

加入節點時,會重新列印一遍叢集原先的主從劃分,最後提示:[OK] New node added correctly,代表節點加入成功。

按照上面的步驟,我們把8008也加入到叢集,可以發現這次列印的叢集資訊,相比上次多了一個主節點8007:

[root@master redis-6.2.1]# src/redis-cli -a 123456 --cluster add-node 192.168.6.86:8008 192.168.6.86:8001

Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.

>>> Adding node 192.168.6.86:8008 to cluster 192.168.6.86:8001

>>> Performing Cluster Check (using node 192.168.6.86:8001)

M: 28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001

   slots:[0-5460] (5461 slots) master

   1 additional replica(s)

S: aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006

   slots: (0 slots) slave

   replicates 28ad6b59866832b13dbd58dd944e641862702e23

M: baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002

   slots:[5461-10922] (5462 slots) master

   1 additional replica(s)

S: 9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005

   slots: (0 slots) slave

   replicates 115a626ee6d475076b096181ab10d3ab6988cc04

M: 115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003

   slots:[10923-16383] (5461 slots) master

   1 additional replica(s)

M: 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367 192.168.6.86:8007

   slots: (0 slots) master

S: 54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004

   slots: (0 slots) slave

   replicates baf630fe745d9f1db7a58ffb96e180fab1047c79

[OK] All nodes agree about slots configuration.

>>> Check for open slots...

>>> Check slots coverage...

[OK] All 16384 slots covered.

>>> Send CLUSTER MEET to node 192.168.6.86:8008 to make it join the cluster.

[OK] New node added correctly.

如果我們列印叢集資訊,會發現8007和8008兩個節點都是主節點,而且叢集並沒有給這兩個節點劃分槽位,這是正常的,新加入到叢集的節點都是主節點,兩個節點的主從關係,以及節點管理的槽位需要我們手動去劃分:

192.168.6.86:8001> CLUSTER NODES

aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006@18006 slave 28ad6b59866832b13dbd58dd944e641862702e23 0 1618318693000 1 connected

baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002@18002 master - 0 1618318692000 2 connected 5461-10922

9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005@18005 slave 115a626ee6d475076b096181ab10d3ab6988cc04 0 1618318693725 3 connected

115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003@18003 master - 0 1618318695730 3 connected 10923-16383

5cd842f76c141eddf5270218b877a54a0c202998 192.168.6.86:8008@18008 master - 0 1618318690000 0 connected

5846d4b7785447b9d7b1c08a0ed74c5e68f2f367 192.168.6.86:8007@18007 master - 0 1618318694728 7 connected

54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004@18004 slave baf630fe745d9f1db7a58ffb96e180fab1047c79 0 1618318691000 2 connected

28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001@18001 myself,master - 0 1618318692000 1 connected 0-5460

我們先連線到8008節點,讓8008節點成為8007的從節點,這裡我們用CLUSTER REPLICATE {masterID}命令,可以指定一個新加入的主節點,成為另一個主節點的從節點,這裡masterID我們用8007的ID:

[root@master redis-6.2.1]# src/redis-cli -a 123456 -c -p 8008

127.0.0.1:8008> CLUSTER REPLICATE 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367

OK

#檢視節點資訊可以看到,8008已經成為8007的從節點

127.0.0.1:8008> CLUSTER NODES

baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002@18002 master - 0 1618318835003 2 connected 5461-10922

5846d4b7785447b9d7b1c08a0ed74c5e68f2f367 192.168.6.86:8007@18007 master - 0 1618318835000 7 connected

54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004@18004 slave baf630fe745d9f1db7a58ffb96e180fab1047c79 0 1618318834000 2 connected

28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001@18001 master - 0 1618318832000 1 connected 0-5460

115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003@18003 master - 0 1618318832999 3 connected 10923-16383

5cd842f76c141eddf5270218b877a54a0c202998 192.168.6.86:8008@18008 myself,slave 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367 0 1618318833000 7 connected

9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005@18005 slave 115a626ee6d475076b096181ab10d3ab6988cc04 0 1618318832000 3 connected

aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006@18006 slave 28ad6b59866832b13dbd58dd944e641862702e23 0 1618318836006 1 connected

在劃分好新的主從後,我們要為新主從分配槽位,這裡我們要用--cluster reshard命令:

[root@master redis-6.2.1]# src/redis-cli -a 123456 --cluster reshard 192.168.6.86:8001

>>> Performing Cluster Check (using node 192.168.6.86:8001)

M: 28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001

   slots:[0-5460] (5461 slots) master

   1 additional replica(s)

S: aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006

   slots: (0 slots) slave

   replicates 28ad6b59866832b13dbd58dd944e641862702e23

M: baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002

   slots:[5461-10922] (5462 slots) master

   1 additional replica(s)

S: 9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005

   slots: (0 slots) slave

   replicates 115a626ee6d475076b096181ab10d3ab6988cc04

M: 115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003

   slots:[10923-16383] (5461 slots) master

   1 additional replica(s)

S: 5cd842f76c141eddf5270218b877a54a0c202998 192.168.6.86:8008

   slots: (0 slots) slave

   replicates 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367

M: 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367 192.168.6.86:8007

   slots: (0 slots) master

   1 additional replica(s)

S: 54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004

   slots: (0 slots) slave

   replicates baf630fe745d9f1db7a58ffb96e180fab1047c79

[OK] All nodes agree about slots configuration.

>>> Check for open slots...

>>> Check slots coverage...

[OK] All 16384 slots covered.

#從8001移出600個槽位給別的主節點

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

#輸入8007主節點的ID,會將8001主節點管理的600個槽位移給8007

What is the receiving node ID? 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367

Please enter all the source node IDs.

#輸入all會從每個主節點(8001、8002、8003)取600個槽位分配給目標主節點(8007)管理

  Type 'all' to use all the nodes as source nodes for the hash slots.

#輸入done則指定從哪些節點取槽位分配給目標主節點管理

  Type 'done' once you entered all the source nodes IDs.

#這裡我們輸入all,讓叢集自動幫我們去各個主節點取槽位,由於要取600個,這裡輸出會很多,只節選部分,可以看到最高到8003主節點的11121

Source node #1: all

……

    Moving slot 11119 from 115a626ee6d475076b096181ab10d3ab6988cc04

    Moving slot 11120 from 115a626ee6d475076b096181ab10d3ab6988cc04

    Moving slot 11121 from 115a626ee6d475076b096181ab10d3ab6988cc04

#輸入yes,讓Redis開始執行槽位分配。

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

槽位分配完畢後,我們再來看看各個主節點的槽位劃分,可以8001、8002、8003現在管理的槽位已經和原先不同,而8007則管理三個槽位,分別是從8001、8002、8003分配過來的[0,198] 、[5461,5661]、 [10923,11121]:

127.0.0.1:8001> CLUSTER NODES

aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006@18006 slave 28ad6b59866832b13dbd58dd944e641862702e23 0 1618319470349 1 connected

baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002@18002 master - 0 1618319472353 2 connected 5662-10922

9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005@18005 slave 115a626ee6d475076b096181ab10d3ab6988cc04 0 1618319469347 3 connected

115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003@18003 master - 0 1618319471351 3 connected 11122-16383

5cd842f76c141eddf5270218b877a54a0c202998 192.168.6.86:8008@18008 slave 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367 0 1618319469000 7 connected

5846d4b7785447b9d7b1c08a0ed74c5e68f2f367 192.168.6.86:8007@18007 master - 0 1618319470000 7 connected 0-198 5461-5661 10923-11121

54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004@18004 slave baf630fe745d9f1db7a58ffb96e180fab1047c79 0 1618319468345 2 connected

28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001@18001 myself,master - 0 1618319470000 1 connected 199-5460

我們來嘗試移除節點,我們先移除8008從節點,這裡我們使用--cluster del-node {host}:{port} {nodeID}從叢集移除從節點:

[root@master redis-6.2.1]# src/redis-cli -a 123456 --cluster del-node 192.168.6.86:8008 5cd842f76c141eddf5270218b877a54a0c202998

>>> Removing node 5cd842f76c141eddf5270218b877a54a0c202998 from cluster 192.168.6.86:8008

>>> Sending CLUSTER FORGET messages to the cluster...

>>> Sending CLUSTER RESET SOFT to the deleted node.

我們再移除8007主節點,由於8007節點已經分配了槽位,直接移除會報錯,這裡我們要先把8007的槽位歸還給各個主節點,這裡我們依舊使用

--cluster reshard將8007現有的節點重新劃分:

#重新劃分8007主節點的槽位

[root@master redis-6.2.1]# src/redis-cli -a 123456 --cluster reshard 192.168.6.86:8007

>>> Performing Cluster Check (using node 192.168.6.86:8007)

M: 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367 192.168.6.86:8007

   slots:[0-198],[5461-5661],[10923-11121] (599 slots) master

M: 28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001

   slots:[199-5460] (5262 slots) master

   1 additional replica(s)

S: 54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004

   slots: (0 slots) slave

   replicates baf630fe745d9f1db7a58ffb96e180fab1047c79

M: baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002

   slots:[5662-10922] (5261 slots) master

   1 additional replica(s)

M: 115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003

   slots:[11122-16383] (5262 slots) master

   1 additional replica(s)

S: aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006

   slots: (0 slots) slave

   replicates 28ad6b59866832b13dbd58dd944e641862702e23

S: 9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005

   slots: (0 slots) slave

   replicates 115a626ee6d475076b096181ab10d3ab6988cc04

[OK] All nodes agree about slots configuration.

>>> Check for open slots...

>>> Check slots coverage...

[OK] All 16384 slots covered.

#原先劃分給8007節點有600個槽位,現在要重新劃分出去

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

#填寫接受槽位節點,這裡填8001

What is the receiving node ID? 28ad6b59866832b13dbd58dd944e641862702e23

Please enter all the source node IDs.

  Type 'all' to use all the nodes as source nodes for the hash slots.

  Type 'done' once you entered all the source nodes IDs.

#填寫8007節點ID

Source node #1: 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367

#輸入done生成槽位遷移計劃

Source node #2: done

……

    Moving slot 11119 from 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367

    Moving slot 11120 from 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367

    Moving slot 11121 from 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367

#輸入yes開始槽位遷移,根據下面的輸出我們可以看到11119、11120、11121被遷移到8001主節點

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

……

Moving slot 11119 from 192.168.6.86:8007 to 192.168.6.86:8001:

Moving slot 11120 from 192.168.6.86:8007 to 192.168.6.86:8001:

Moving slot 11121 from 192.168.6.86:8007 to 192.168.6.86:8001:

8007主節點將槽位重新分配後,並不意味著8001、8002、8003管理的槽位會回到最初,可以看到,8001管理兩個槽位[0,5661]、[10923,11121],和最初8001管理[0-5460]已經不一樣了,這裡就不再對比8002和8003,大家可以自行對比:

192.168.6.86:8001> CLUSTER NODES

aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006@18006 slave 28ad6b59866832b13dbd58dd944e641862702e23 0 1618651357467 8 connected

baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002@18002 master - 0 1618651357000 2 connected 5662-10922

9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005@18005 slave 115a626ee6d475076b096181ab10d3ab6988cc04 0 1618651356000 3 connected

115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003@18003 master - 0 1618651355000 3 connected 11122-16383

54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004@18004 slave baf630fe745d9f1db7a58ffb96e180fab1047c79 0 1618651355463 2 connected

28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001@18001 myself,master - 0 1618651354000 8 connected 0-5661 10923-11121

在重新分配完槽位後,我們再來看看節點資訊:

127.0.0.1:8001> CLUSTER NODES

aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006@18006 slave 28ad6b59866832b13dbd58dd944e641862702e23 0 1618320346264 8 connected

baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002@18002 master - 0 1618320345000 2 connected 5662-10922

9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005@18005 slave 115a626ee6d475076b096181ab10d3ab6988cc04 0 1618320345000 3 connected

115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003@18003 master - 0 1618320345261 3 connected 11122-16383

5846d4b7785447b9d7b1c08a0ed74c5e68f2f367 192.168.6.86:8007@18007 master - 0 1618320347267 7 connected

54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004@18004 slave baf630fe745d9f1db7a58ffb96e180fab1047c79 0 1618320343256 2 connected

28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001@18001 myself,master - 0 1618320343000 8 connected 0-5661 10923-11121

確定8007已經不再管理任何槽位後,我們將8007節點移出叢集:

[root@master redis-6.2.1]# src/redis-cli -a 123456 --cluster del-node 192.168.6.86:8007 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367

>>> Removing node 5846d4b7785447b9d7b1c08a0ed74c5e68f2f367 from cluster 192.168.6.86:8007

>>> Sending CLUSTER FORGET messages to the cluster...

>>> Sending CLUSTER RESET SOFT to the deleted node.

此時,重新檢視叢集資訊,可以看到不再有8007節點了:

127.0.0.1:8001> CLUSTER NODES

aa6ce37e876660161403a801adb8fc7a79a9d876 192.168.6.86:8006@18006 slave 28ad6b59866832b13dbd58dd944e641862702e23 0 1618360351136 8 connected

baf630fe745d9f1db7a58ffb96e180fab1047c79 192.168.6.86:8002@18002 master - 0 1618360350000 2 connected 5662-10922

9c6f93c3b5329e60032b970b57e599b98961cba6 192.168.6.86:8005@18005 slave 115a626ee6d475076b096181ab10d3ab6988cc04 0 1618360350132 3 connected

115a626ee6d475076b096181ab10d3ab6988cc04 192.168.6.86:8003@18003 master - 0 1618360348127 3 connected 11122-16383

54b6c985bf0f41fa1b92cff7c165c317dd0a30c7 192.168.6.86:8004@18004 slave baf630fe745d9f1db7a58ffb96e180fab1047c79 0 1618360351000 2 connected

28ad6b59866832b13dbd58dd944e641862702e23 192.168.6.86:8001@18001 myself,master - 0 1618360350000 8 connected 0-5661 10923-11121

以上就是比較幾種Redis叢集方案的詳細內容,更多關於Redis叢集方案的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com