1. 程式人生 > >Redis叢集搭建之Redis Cluster實踐

Redis叢集搭建之Redis Cluster實踐

之前一直有用redis,但也一直停留在用的階段,自己也單機部署過玩玩,但總感覺不深入,所以現在繼續研究研究redis叢集,下面就根據自己學習實踐,記錄下使用Redis官網提供的Redis叢集方案;

Redis Cluster背景介紹

Redis Cluster與Redis3.0.0同時釋出,以此結束了Redis無官方叢集方案的時代,目前,Redis已經發布了3.0.7版本。

redis cluster是去中心化,去中介軟體的,也就是說,叢集中的每個節點都是平等的關係,都是對等的,每個節點都儲存各自的資料和整個叢集的狀態。每個節點都和其他所有節點連線,而且這些連線保持活躍,這樣就保證了我們只需要連線叢集中的任意一個節點,就可以獲取到其他節點的資料。

那麼redis 是如何合理分配這些節點和資料的呢?

Redis 叢集沒有並使用傳統的一致性雜湊來分配資料,而是採用另外一種叫做雜湊槽 (hash slot)的方式來分配的。redis cluster 預設分配了 16384 個slot,當我們set一個key 時,會用CRC16演算法來取模得到所屬的slot,然後將這個key 分到雜湊槽區間的節點上,具體演算法就是:CRC16(key) % 16384。

注意的是:必須要3個以後的主節點,否則在建立叢集時會失敗,我們在後續會實踐到。

所以,我們假設現在有3個節點已經組成了叢集,分別是:A, B, C 三個節點,它們可以是一臺機器上的三個埠,也可以是三臺不同的伺服器。那麼,採用雜湊槽 (hash slot)的方式來分配16384個slot 的話,它們三個節點分別承擔的slot 區間是:

  • 節點A覆蓋0-5460;
  • 節點B覆蓋5461-10922;
  • 節點C覆蓋10923-16383.

那麼,現在我想設定一個key ,比如叫my_name:

set my_name wind

按照redis cluster的雜湊槽演算法:CRC16(‘my_name’)%16384 = 2412。 那麼就會把這個key 的儲存分配到 A 上了。

同樣,當我連線(A,B,C)任何一個節點想獲取my_name這個key時,也會這樣的演算法,然後內部跳轉到B節點上獲取資料。

這種雜湊槽的分配方式有好也有壞,好處就是很清晰,比如我想新增一個節點D,redis cluster的這種做法是從各個節點的前面各拿取一部分slot到D上,我會在接下來的實踐中實驗。大致就會變成這樣:

  • 節點A覆蓋1365-5460
  • 節點B覆蓋6827-10922
  • 節點C覆蓋12288-16383
  • 節點D覆蓋0-1364,5461-6826,10923-12287

同樣刪除一個節點也是類似,移動完成後就可以刪除這個節點了。

Redis Cluster主從模式

redis cluster 為了保證資料的高可用性,加入了主從模式,一個主節點對應一個或多個從節點,主節點提供資料存取,從節點則是從主節點拉取資料備份,當這個主節點掛掉後,就會有這個從節點選取一個來充當主節點,從而保證叢集不會掛掉。

上面那個例子裡, 叢集有ABC三個主節點, 如果這3個節點都沒有加入從節點,如果B掛掉了,我們就無法訪問整個叢集了。A和C的slot也無法訪問。

所以我們在叢集建立的時候,一定要為每個主節點都添加了從節點, 比如像這樣, 叢集包含主節點A、B、C, 以及從節點A1、B1、C1, 那麼即使B掛掉系統也可以繼續正確工作。

B1節點替代了B節點,所以Redis叢集將會選擇B1節點作為新的主節點,叢集將會繼續正確地提供服務。 當B重新開啟後,它就會變成B1的從節點。

不過需要注意,如果節點B和B1同時掛了,Redis叢集就無法繼續正確地提供服務了。

redis cluster 動手實踐

[root@spg redis-claster]# tar -zxvf redis-3.0.5.tar.gz

2.安裝

[root@spg redis-claster]#cd redis-3.0.5
[root@spg redis-3.0.5]#make && make install

3.將redis-trib.rb 複製到/usr/local/bin

[root@spg redis-3.0.5]#cp src/redis-trib.rb /usr/local/bin

4.開始叢集搭建,首先修改配置檔案。

[root@spg redis-3.0.5]#vi redis.conf
修改如下幾處:
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

新建6個節點(注意:Redis Cluster要求至少6個節點,3主3備,否則構建叢集會報錯):

#這裡檔名就按埠號命名,方便區分。
[root@spg redis-claster]# mkdir 7000
[root@spg redis-claster]# mkdir 7001
[root@spg redis-claster]# mkdir 7002
[root@spg redis-claster]# mkdir 7003
[root@spg redis-claster]# mkdir 7004
[root@spg redis-claster]# mkdir 7005

將redis.conf 分別拷貝到這6個資料夾中,並修改其中對應的埠號。
分別啟動6個Redis。

[root@spg redis-claster]# cd 7000
[root@spg 7000]# redis-server redis.conf &
#其他幾個啟動略...

可通過檢視程序檢視各redis是否已經正常啟動。

[[email protected] redis-claster]# ps -ef | grep redis
root      6568  6127  0 21:50 pts/0    00:00:03 redis-server *:7000 [cluster]
root      6590  6127  0 21:50 pts/0    00:00:02 redis-server *:7001 [cluster]
root      6607  6127  0 21:51 pts/0    00:00:02 redis-server *:7002 [cluster]
root      6613  6127  0 21:51 pts/0    00:00:01 redis-server *:7003 [cluster]
root      6888  6127  0 22:02 pts/0    00:00:00 redis-server *:7004 [cluster]
root      6905  6127  0 22:03 pts/0    00:00:00 redis-server *:7005 [cluster]

接著將6個Redis加入叢集。
需要用到的命令就是redis-trib.rb,這是官方的一個用ruby寫的一個操作redis cluster的命令,所以,你的機器上需要安裝ruby。我們先試一下這個命令:

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

因為我們要新建叢集, 所以這裡使用create命令. –replicas 1 引數表示為每個主節點建立一個從節點. 其他引數是例項的地址集合。

由於我機子上沒安裝ruby,所以,會報錯:

[root@spg 7003]# 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
/usr/bin/env: ruby: 沒有那個檔案或目錄

通過如下命令安裝ruby:

[root@spg 7003]# yum install ruby ruby-devel rubygems rpm-build

完成後繼續執行,結果還是報錯:

[[email protected] 7003]# 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
/usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- redis (LoadError)
    from /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require'
    from /usr/local/bin/redis-trib.rb:25:in `<main>'

這是因為ruby和redis的連線沒安裝好:

[root@spg 7003]# gem install redis
Fetching: redis-3.2.2.gem (100%)
Successfully installed redis-3.2.2
Parsing documentation for redis-3.2.2
Installing ri documentation for redis-3.2.2
1 gem installed

安裝完後再建立叢集。

[[email protected] redis-claster]# 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
>>> Creating cluster
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7005: OK
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:7000
127.0.0.1:7001
127.0.0.1:7002
Adding replica 127.0.0.1:7003 to 127.0.0.1:7000
Adding replica 127.0.0.1:7004 to 127.0.0.1:7001
Adding replica 127.0.0.1:7005 to 127.0.0.1:7002
M: be26c521481afcd6e739e2bfef69e9dcfb63d0a6 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: ce06b13387702c3ee63e0118dd10c5f81a1285b5 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: 947cc4a9e890672cfad4806a5921e9f8bdf05c05 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
S: 1da8a7f4c3cd5d7537e90e0ca5f4fb416f41a40c 127.0.0.1:7003
   replicates be26c521481afcd6e739e2bfef69e9dcfb63d0a6
S: 05ac96f9cdee679f98e8f7ce8e97cf1cbea608ca 127.0.0.1:7004
   replicates ce06b13387702c3ee63e0118dd10c5f81a1285b5
S: b65f33d97416795226964aa22f3b4a8ac7366a99 127.0.0.1:7005
   replicates 947cc4a9e890672cfad4806a5921e9f8bdf05c05
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
6568:M 27 Feb 22:07:57.661 # configEpoch set to 1 via CLUSTER SET-CONFIG-EPOCH
6590:M 27 Feb 22:07:57.661 # configEpoch set to 2 via CLUSTER SET-CONFIG-EPOCH
6607:M 27 Feb 22:07:57.662 # configEpoch set to 3 via CLUSTER SET-CONFIG-EPOCH
6613:M 27 Feb 22:07:57.663 # configEpoch set to 4 via CLUSTER SET-CONFIG-EPOCH
6888:M 27 Feb 22:07:57.664 # configEpoch set to 5 via CLUSTER SET-CONFIG-EPOCH
6905:M 27 Feb 22:07:57.664 # configEpoch set to 6 via CLUSTER SET-CONFIG-EPOCH
>>> Sending CLUSTER MEET messages to join the cluster
6568:M 27 Feb 22:07:57.749 # IP address for this node updated to 127.0.0.1
6590:M 27 Feb 22:07:57.751 # IP address for this node updated to 127.0.0.1
6613:M 27 Feb 22:07:57.751 # IP address for this node updated to 127.0.0.1
6607:M 27 Feb 22:07:57.853 # IP address for this node updated to 127.0.0.1
6905:M 27 Feb 22:07:57.853 # IP address for this node updated to 127.0.0.1
6888:M 27 Feb 22:07:57.853 # IP address for this node updated to 127.0.0.1
Waiting for the cluster to join....6568:M 27 Feb 22:08:02.646 # Cluster state changed: ok

6613:S 27 Feb 22:08:02.720 # Cluster state changed: ok
6590:M 27 Feb 22:08:02.722 # Cluster state changed: ok
6888:S 27 Feb 22:08:02.723 # Cluster state changed: ok
6905:S 27 Feb 22:08:02.724 # Cluster state changed: ok
>>> Performing Cluster Check (using node 127.0.0.1:7000)
6607:M 27 Feb 22:08:02.747 # Cluster state changed: ok
M: be26c521481afcd6e739e2bfef69e9dcfb63d0a6 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: ce06b13387702c3ee63e0118dd10c5f81a1285b5 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: 947cc4a9e890672cfad4806a5921e9f8bdf05c05 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
M: 1da8a7f4c3cd5d7537e90e0ca5f4fb416f41a40c 127.0.0.1:7003
   slots: (0 slots) master
   replicates be26c521481afcd6e739e2bfef69e9dcfb63d0a6
M: 05ac96f9cdee679f98e8f7ce8e97cf1cbea608ca 127.0.0.1:7004
   slots: (0 slots) master
   replicates ce06b13387702c3ee63e0118dd10c5f81a1285b5
M: b65f33d97416795226964aa22f3b4a8ac7366a99 127.0.0.1:7005
   slots: (0 slots) master
   replicates 947cc4a9e890672cfad4806a5921e9f8bdf05c05
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

OK,從上面可看出叢集已經建立成果,最後再檢查叢集各節點狀態:

[[email protected] redis-3.0.5]# redis-trib.rb check 127.0.0.1:7000
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7003: OK
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: be26c521481afcd6e739e2bfef69e9dcfb63d0a6 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: 947cc4a9e890672cfad4806a5921e9f8bdf05c05 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: 05ac96f9cdee679f98e8f7ce8e97cf1cbea608ca 127.0.0.1:7004
   slots: (0 slots) slave
   replicates ce06b13387702c3ee63e0118dd10c5f81a1285b5
S: b65f33d97416795226964aa22f3b4a8ac7366a99 127.0.0.1:7005
   slots: (0 slots) slave
   replicates 947cc4a9e890672cfad4806a5921e9f8bdf05c05
M: ce06b13387702c3ee63e0118dd10c5f81a1285b5 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: 1da8a7f4c3cd5d7537e90e0ca5f4fb416f41a40c 127.0.0.1:7003
   slots: (0 slots) slave
   replicates be26c521481afcd6e739e2bfef69e9dcfb63d0a6
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

從上面結果可看出叢集中6個節點均正常,其中有3個主節點,3個從節點。

5.測試叢集連結狀況
剛才叢集搭建成功了。按照redis cluster的特點,它是去中心化,每個節點都是對等的,所以,你連線哪個節點都可以獲取和設定資料,我們來試一下。

redis-cli是redis預設的客戶端工具,啟動時加上`-c`引數,就可以連線到叢集。
連線任意一個節點埠:

[root@spg 7006]# redis-cli -c -p 7003
127.0.0.1:7003>

設定值:

127.0.0.1:7003> set my_name wind
-> Redirected to slot [12803] located at 127.0.0.1:7002
OK
127.0.0.1:7002> get my_name
"wind"

前面說過Redis Cluster值分配規則,所以分配key的時候,它會使用CRC16(‘my_name’)%16384演算法,來計算,將這個key 放到哪個節點,這裡分配到了12803slot 就分配到了7002(10923-16383)這個節點上。所以有:

Redirected to slot [12803] located at 127.0.0.1:7002

同樣,連結其他節點也可獲取剛設定的資料,也可以設定其他值測試其key分配。

6.測試叢集中某節點宕機情況
上面我們建立來了一個叢集。3個主節點[7000-7002]提供資料儲存和讀取,3個從節點[7003-7005]則是負責把[7000-7002]的資料同步到自己的節點上來,我們來看一下[7003-7005]的appendonly.aof的內容,驗證是不是說的這樣,我們看7005節點資料:

[root@spg 7005]# vim appendonly.aof 

*2                                                                                                                                                   
$6
SELECT
$1
0
*3
$3
set
$7
my_name
$4
wind

我們看下,的確是從7000節點上同步過來的資料,7003,7004也是。

下面,我們先來模擬其中一臺Master主伺服器掛掉的情況,那就7000掛掉吧:

[root@spg 7005]# ps -ef | grep redis
root      3027  2974  0 20:03 pts/0    00:00:04 redis-server *:7000 [cluster]
root      3063  2974  0 20:04 pts/0    00:00:03 redis-server *:7001 [cluster]
root      3081  2974  0 20:05 pts/0    00:00:03 redis-server *:7002 [cluster]
root      3093  2974  0 20:05 pts/0    00:00:03 redis-server *:7003 [cluster]
root      3109  2974  0 20:06 pts/0    00:00:02 redis-server *:7004 [cluster]
root      3123  2974  0 20:06 pts/0    00:00:02 redis-server *:7005 [cluster]
root      3406  2974  0 20:23 pts/0    00:00:00 grep --color=auto redis
[root@spg 7005]# kill -9 3027

好,按照前面的理論,7000主節點掛掉了,那麼這個時候,7000的從節點只有7003一個,肯定7003就會被選舉稱Master節點了:

[[email protected] 7005]# redis-trib.rb check 127.0.0.1:7001
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7004: OK
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: ce06b13387702c3ee63e0118dd10c5f81a1285b5 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: b65f33d97416795226964aa22f3b4a8ac7366a99 127.0.0.1:7005
   slots: (0 slots) slave
   replicates 947cc4a9e890672cfad4806a5921e9f8bdf05c05
M: 947cc4a9e890672cfad4806a5921e9f8bdf05c05 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
M: 1da8a7f4c3cd5d7537e90e0ca5f4fb416f41a40c 127.0.0.1:7003
   slots:0-5460 (5461 slots) master
   0 additional replica(s)
S: 05ac96f9cdee679f98e8f7ce8e97cf1cbea608ca 127.0.0.1:7004
   slots: (0 slots) slave
   replicates ce06b13387702c3ee63e0118dd10c5f81a1285b5
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

看了下,上面有了三個M 節點了,果真,7003被選取成了替代7000成為主節點了。如果前面在7000節點上存有資料,此時連線redis,7000節點上資料依然可正常獲取,因為資料已經同步到其備機7003上。

OK。我們再來模擬 7000節點重新啟動了的情況,那麼它還會自動加入到叢集中嗎?那麼,7000這個節點上充當什麼角色呢? 我們試一下:

[root@spg 7005]# cd ../7000   
[root@spg 7000]# redis-server redis.conf &

啟動完成後再驗證叢集狀態,同時檢視叢集中7000角色

[[email protected] 7000]# redis-trib.rb check 127.0.0.1:7000
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7005: OK
>>> Performing Cluster Check (using node 127.0.0.1:7000)
S: be26c521481afcd6e739e2bfef69e9dcfb63d0a6 127.0.0.1:7000
   slots: (0 slots) slave
   replicates 1da8a7f4c3cd5d7537e90e0ca5f4fb416f41a40c
M: 1da8a7f4c3cd5d7537e90e0ca5f4fb416f41a40c 127.0.0.1:7003
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: 947cc4a9e890672cfad4806a5921e9f8bdf05c05 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: 05ac96f9cdee679f98e8f7ce8e97cf1cbea608ca 127.0.0.1:7004
   slots: (0 slots) slave
   replicates ce06b13387702c3ee63e0118dd10c5f81a1285b5
M: ce06b13387702c3ee63e0118dd10c5f81a1285b5 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: b65f33d97416795226964aa22f3b4a8ac7366a99 127.0.0.1:7005
   slots: (0 slots) slave
   replicates 947cc4a9e890672cfad4806a5921e9f8bdf05c05
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

由上面可知7000已經正常,但是作為了7003的備機存在。

總結:至此,基於Redis官網的Redis Cluster解決方案,完成了Redis叢集的搭建,過程稍微複雜,但相信熟練起來就會很順手,後面會繼續實踐叢集中節點的增減情況。