作者:ITPSC;
出處:http://www.cnblogs.com/hjwublog/


Redis集羣簡介

Redis 集羣是3.0之後才引入的,在3.0之前,使用哨兵(sentinel)機制(本文將不做介紹,大家可另行查閱)來監控各個節點之間的狀態。Redis 集羣可謂是讓很多人久等了。

Redis 集羣是一組能進行數據共享的Redis 實例(服務或者節點)的設施,集羣可以使用的功能是普通單機 Redis 所能使用的功能的一個子集;Redis 集羣通常具有高可用、可擴展性、分佈式、容錯等特性。瞭解redis的集羣後,這些晦澀的概念可結合redis的主從、集羣分區和集羣運維等角度理解體會。


Redis集羣搭建

創建集羣文件夾

在/usr/local/下新建redis-cluster目錄並在redis-cluster下新建7031~7036共6個文件夾,這6個文件夾代表創建redis集羣的6個節點。如下

[root@localhost local]# mkdir -p /usr/local/redis-cluster
[root@localhost redis-cluster]# mkdir 7031 7032 7033 7034 7035 7036

拷貝修改配置文件

將已有的/usr/local/redis/etc/下的redis.conf拷貝到新創建的7031目錄中

[root@localhost etc]# cp redis.conf /usr/local/redis-cluster/7031
[root@localhost 7031]# vi redis.conf

修改項如下:

(1)綁定端口,port 7031

(2)綁定IP,bind 192.168.2.128

(3)指定數據存放路徑,dir /usr/local/redis-cluster/7031

(4)啓動集羣模式,cluster-enabled yes

(5)指定集羣節點配置文件,cluster-config-file nodes-7031.conf

(6)後臺啓動,daemonize yes

(7)指定集羣節點超時時間,cluster-node-timeout 5000

(8)指定持久化方式,appendonly yes

上面紅色項目最好全部設置,不然會出意想不到的錯誤,703x最好與節點文件夾保持一致。

將7031的redis.conf改完後再拷貝到剩下的5個目錄中,然後只要全局替換redis.conf中的7031爲相應的節點即可。

安裝ruby

由於Redis 集羣客戶端實現很少,redis集羣的啓動需要用到ruby實現的redis-trib.rb,所以我們需要先安裝ruby。

[root@localhost redis-cluster]# yum install ruby
[root@localhost redis-cluster]# yum install rubygems
[root@localhost redis-cluster]# gem install redis

啓動redis實例

[root@localhost redis-cluster]# 
/usr/local/redis/bin/redis-server /usr/local/redis-cluster/7031/redis.conf

分別啓動6個redis實例。也可以用腳本循環啓動,這樣更方便省時

[root@localhost redis-cluster]#
for((i=1;i<=6;i++)); do /usr/local/redis/bin/redis-server /usr/local/redis-cluster/703$i/redis.conf; done


查看redis實例是否啓動成功

[root@localhost redis-cluster]# netstat -tunpl | grep redis-server
#或者
[root@localhost redis-cluster]# ps -ef | grep redis-server

分佈式緩存技術redis系列:redis高級應用(搭建、分區原理、操作)


創建並啓動集羣

進入redis安裝目錄的bin目錄下

[root@localhost ~]# cd /usr/local/redis/bin/
[root@localhost bin]#./redis-trib.rb create --replicas 1 192.168.2.128:7031 192.168.2.128:7032 192.168.2.128:7033 192.168.2.128:7034 192.168.2.128:7035 192.168.2.128:7036


命令的意義如下:

給定 redis-trib.rb 程序的命令是 create,表示創建一個新的集羣。選項 --replicas 1 表示爲集羣中的每個主節點創建一個從節點。之後跟着的其他參數則是實例的地址列表, 指定使用這些地址所指示的實例來創建新集羣。

 
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.2.128:7031
192.168.2.128:7032
192.168.2.128:7033
Adding replica 192.168.2.128:7034 to 192.168.2.128:7031
Adding replica 192.168.2.128:7035 to 192.168.2.128:7032
Adding replica 192.168.2.128:7036 to 192.168.2.128:7033
......
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.


“All 16384 slots covered.”表示集羣中的 16384 個槽都有至少一個主節點在處理, 集羣運作正常。從打印出來的信息也可以看出,7031,7032,7033是主節點,其它三個是從節點。

客戶端連接集羣

集羣啓動成功後,我們就可以用任意一個客戶端連接集羣了,如下

[root@localhost bin]# /usr/local/redis/bin/redis-cli -c -h 192.168.2.128 -p 7031
192.168.2.128:7031> info
# Server
redis_version:3.2.0
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:f8fcffd133fe3364
redis_mode:cluster
os:Linux 2.6.32-504.el6.x86_64 x86_64
arch_bits:64


可以使用 cluster info命令查看集羣信息,cluster nodes命令查看集羣節點信息。

集羣關閉

關閉集羣需要逐個關閉

[root@localhost redis-cluster]#
for((i=1;i<=6;i++)); do /usr/local/redis/bin/redis-cli -c -h 192.168.2.128 -p 703$i shutdown; done

如果重新啓動集羣報以下錯誤

 
[ERR] Node 192.168.2.128:7031 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.

需要清除殺掉redis實例,然後刪除每個節點下的臨時數據文件appendonly.aof,dump.rdb,nodes-703x.conf,然後再重新啓動redis實例即可啓動集羣。

 
[root@localhost redis-cluster]#for((i=1;i<=6;i++)); do cd 703$i; rm -rf appendonly.aof; rm -rf dump.rdb; rm -rf nodes-703$i.conf; cd ..; done

集羣測試

下面我們先來體驗一下集羣的set,get簡單操作,後面我們會進一步學習集羣的更多操作。

192.168.2.128:7031> set name "zhangsan"
-> Redirected to slot [5798] located at 192.168.2.128:7032
OK
192.168.2.128:7032> set age 20
-> Redirected to slot [741] located at 192.168.2.128:7031
OK
192.168.2.128:7031> set sex "man"
OK
192.168.2.128:7031>

如果在連接客戶端的時候不加-c選項set key時則會報MOVED 的錯誤:

[root@localhost bin]# /usr/local/redis/bin/redis-cli -h 192.168.2.128 -p 7031
192.168.2.128:7031> set name "zhangsan"
(error) MOVED 5798 192.168.2.128:7032
192.168.2.128:7031> set age 20
OK
192.168.2.128:7031> set sex "man"
OK
192.168.2.128:7031>


來看看取值又是怎麼樣

 
192.168.2.128:7031> get name
-> Redirected to slot [5798] located at 192.168.2.128:7032
"zhangsan"
192.168.2.128:7032> get age
-> Redirected to slot [741] located at 192.168.2.128:7031
"20"
192.168.2.128:7031> get sex
"man"
192.168.2.128:7031>


可以看到,客戶端連接加-c選項的時候,存儲和提取key的時候不斷在7031和7032之間跳轉,這個稱爲客戶端重定向。之所以發生客戶端重定向,是因爲Redis Cluster中的每個Master節點都會負責一部分的槽(slot),存取的時候都會進行鍵值空間計算定位key映射在哪個槽(slot)上,如果映射的槽(slot)正好是當前Master節點負責則直接存取,否則就跳轉到其他Master節點負的槽(slot)中存取,這個過程對客戶端是透明的。繼續看下文的集羣分區原理。


Redis集羣分區原理

槽(slot)的基本概念

從上面集羣的簡單操作中,我們已經知道redis存取key的時候,都要定位相應的槽(slot)。

Redis 集羣鍵分佈算法使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現: 一個 Redis 集羣包含 16384 個哈希槽(hash slot), 它們的編號爲0、1、2、3……16382、16383,這個槽是一個邏輯意義上的槽,實際上並不存在。redis中的每個key都屬於這 16384 個哈希槽的其中一個,存取key時都要進行key->slot的映射計算。

下面我們來看看啓動集羣時候打印的信息:

 
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.2.128:7031
192.168.2.128:7032
192.168.2.128:7033
Adding replica 192.168.2.128:7034 to 192.168.2.128:7031
Adding replica 192.168.2.128:7035 to 192.168.2.128:7032
Adding replica 192.168.2.128:7036 to 192.168.2.128:7033
M: bee706db5ae182c5be9b9bdf94c2d6f3f8c8ec5c 192.168.2.128:7031
slots:0-5460 (5461 slots) master
M: 72826f06dbf3be163f2f456ca24caed76a15bdf4 192.168.2.128:7032
slots:5461-10922 (5462 slots) master
M: ab6e9d1dfc471225eef01e57be563157f81d26b3 192.168.2.128:7033
slots:10923-16383 (5461 slots) master
......
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.


從上面信息可以看出,創建集羣的時候,哈希槽被分配到了三個主節點上,從節點是沒有哈希槽的。7031負責編號爲0-5460 共5461個 slots,7032負責編號爲 5461-10922共5462 個 slots,7033負責編號爲10923-16383 共5461個 slots。

鍵-槽映射算法

和memcached一樣,redis也採用一定的算法進行鍵-槽(key->slot)之間的映射。memcached採用一致性哈希(consistency hashing)算法進行鍵-節點(key-node)之間的映射,而redis集羣使用集羣公式來計算鍵 key 屬於哪個槽:

 
HASH_SLOT(key)= CRC16(key) % 16384


其中 CRC16(key) 語句用於計算鍵 key 的 CRC16 校驗和 。key經過公式計算後得到所對應的哈希槽,而哈希槽被某個主節點管理,從而確定key在哪個主節點上存取,這也是redis將數據均勻分佈到各個節點上的基礎。


分佈式緩存技術redis系列:redis高級應用(搭建、分區原理、操作)


鍵-槽-節點(key->slot->node)映射示意圖

集羣分區好處

無論是memcached的一致性哈希算法,還是redis的集羣分區,最主要的目的都是在移除、添加一個節點時對已經存在的緩存數據的定位影響儘可能的降到最小。redis將哈希槽分佈到不同節點的做法使得用戶可以很容易地向集羣中添加或者刪除節點, 比如說:

l 如果用戶將新節點 D 添加到集羣中, 那麼集羣只需要將節點 A 、B 、 C 中的某些槽移動到節點 D 就可以了。

l 與此類似, 如果用戶要從集羣中移除節點 A , 那麼集羣只需要將節點 A 中的所有哈希槽移動到節點 B 和節點 C , 然後再移除空白(不包含任何哈希槽)的節點 A 就可以了。

因爲將一個哈希槽從一個節點移動到另一個節點不會造成節點阻塞, 所以無論是添加新節點還是移除已存在節點, 又或者改變某個節點包含的哈希槽數量, 都不會造成集羣下線,從而保證集羣的可用性。下面我們就來學習下集羣中節點的增加和刪除。


集羣操作

集羣操作包括查看集羣信息,查看集羣節點信息,向集羣中增加節點、刪除節點,重新分配槽等操作。

查看集羣信息

cluster info 查看集羣狀態,槽分配,集羣大小等,cluster nodes也可查看主從節點。

192.168.2.128:7031> 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_sent:119
cluster_stats_messages_received:119
192.168.2.128:7031>

新增節點

(1)新增節點配置文件

執行下面的腳本創建腳本配置文件

 
[root@localhost redis-cluster]# mkdir /usr/local/redis-cluster/7037 && cp /usr/local/redis-cluster/7031/redis.conf /usr/local/redis-cluster/7037/redis.conf && sed -i "s/7031/7037/g" /usr/local/redis-cluster/7037/redis.conf

(2)啓動新增節點

[root@localhost bin]# /usr/local/redis/bin/redis-server /usr/local/redis-cluster/7037/redis.conf

(3)添加節點到集羣

現在已經添加了新增一個節點所需的配置文件,但是這個這點還沒有添加到集羣中,現在讓它成爲集羣中的一個主節點

[root@localhost redis-cluster]# cd /usr/local/redis/bin/
[root@localhost bin]# ./redis-trib.rb add-node 192.168.2.128:7037 192.168.2.128:7036
>>> Adding node 192.168.2.128:7037 to cluster 192.168.2.128:7036
>>> Performing Cluster Check (using node 192.168.2.128:7036)
S: 2c8d72f1914f9d6052065f7e9910cc675c3c717b 192.168.2.128:7036
slots: (0 slots) slave
replicates 6dbb4aa323864265c9507cf336ef7d3b95ea8d1b
M: 6dbb4aa323864265c9507cf336ef7d3b95ea8d1b 192.168.2.128:7033
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: 791a7924709bfd7ef5c36d9b9c838925e41e3c2e 192.168.2.128:7034
slots: (0 slots) slave
replicates d9e3c78a7c49689c29ab67a8a17be9d95cb08452
M: d9e3c78a7c49689c29ab67a8a17be9d95cb08452 192.168.2.128:7031
slots:0-5460 (5461 slots) master
1 additional replica(s)
M: 69b63d8db629fa8a689dd1ed25ed941c076d4111 192.168.2.128:7032
slots:5461-10922 (5462 slots) master
1 additional replica(s)
S: e669a91866225279aafcac29bf07b826eb5be91c 192.168.2.128:7035
slots: (0 slots) slave
replicates 69b63d8db629fa8a689dd1ed25ed941c076d4111
[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.2.128:7037 to make it join the cluster.
[OK] New node added correctly.
[root@localhost bin]#

./redis-trib.rb add-node 命令中,7037 是新增的主節點,7036 是集羣中已有的從節點。再來看看集羣信息

 
192.168.2.128:7031> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:7
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_sent:11256
cluster_stats_messages_received:11256


分佈式緩存技術redis系列:redis高級應用(搭建、分區原理、操作)


(4)分配槽

從添加主節點輸出信息和查看集羣信息中可以看出,我們已經成功的向集羣中添加了一個主節點,但是這個主節還沒有成爲真正的主節點,因爲還沒有分配槽(slot),也沒有從節點,現在要給它分配槽(slot)

[root@localhost bin]# ./redis-trib.rb reshard 192.168.2.128:7031
>>> Performing Cluster Check (using node 192.168.2.128:7031)
M: 1a544a9884e0b3b9a73db80633621bd90ceff64a 192.168.2.128:7031
......
[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)? 1024
What is the receiving node ID?


系統提示要移動多少個配槽(slot),並且配槽(slot)要移動到哪個節點,任意輸入一個數,如1024,再輸入新增節點的ID cf48228259def4e51e7e74448e05b7a6c8f5713f.

 
What is the receiving node ID? cf48228259def4e51e7e74448e05b7a6c8f5713f
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.
Source node #1:


然後提示要從哪幾個節點中移除1024個槽(slot),這裏輸入‘all’表示從所有的主節點中隨機轉移,湊夠1024個哈希槽,然後就開始從新分配槽(slot)了。從新分配完後再次查看集羣節點信息

分佈式緩存技術redis系列:redis高級應用(搭建、分區原理、操作)


可見,0-340 5461-5802 10923-11263的槽(slot)被分配給了新增加的節點。三個加起來剛好1024個槽(slot)。

(5)指定從節點

現在從節點7036的主節點是7033,現在我們要把他變爲新增加節點(7037)的從節點,需要登錄7036的客戶端

[root@localhost bin]# /usr/local/redis/bin/redis-cli -c -h 192.168.2.128 -p 7036
192.168.2.128:7036> cluster replicate cf48228259def4e51e7e74448e05b7a6c8f5713f
OK


再來查看集羣節點信息

分佈式緩存技術redis系列:redis高級應用(搭建、分區原理、操作)


可見,7036成爲了新增節點7037的從節點。

刪除節點

指定刪除節點的ID即可,如下

[root@localhost bin]#
./redis-trib.rb del-node 192.168.2.128:7037 'a56461a171334560f16652408c2a45e629d268f6'
>>> Removing node a56461a171334560f16652408c2a45e629d268f6 from cluster 192.168.2.128:7037
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
[root@localhost bin]#


集羣操作小結

從上面過程可以看出,添加節點、分配槽、刪除節點的過程,不用停止集羣,不阻塞集羣的其他操作。命令小結

#向集羣中添加節點,7037是新增節點,7036是集羣中已有的節點

./redis-trib.rb add-node 192.168.2.128:7037 192.168.2.128:7036

#重新分配槽

./redis-trib.rb reshard 192.168.2.128:7031

#指定當前節點的主節點

cluster replicate cf48228259def4e51e7e74448e05b7a6c8f5713f

#刪除節點

./redis-trib.rb del-node 192.168.2.128:7037 'a56461a171334560f16652408c2a45e629d268f6'

到此,redis的集羣搭建、分區原理、集羣增加節點以及刪除節點的主要內容已經簡要介紹完畢。


參考文檔

http://redisdoc.com/topic/cluster-tutorial.html
http://blog.51yip.com/nosql/1726.html
相關文章