1. 程式人生 > >redis高級應用(集群搭建、集群分區原理、集群操作)

redis高級應用(集群搭建、集群分區原理、集群操作)

onf -c emca 文件夾 fig host current dump 拷貝

文章主目錄

  • Redis集群簡介
  • Redis集群搭建
  • Redis集群分區原理
  • 集群操作
  • 參考文檔

本文是redis學習系列的第四篇,前面我們學習了redis的數據結構和一些高級特性,點擊下面鏈接可回看

《詳細講解redis數據結構(內存模型)以及常用命令》

《redis高級應用(主從、事務與鎖、持久化)》

本文我們繼續學習redis的高級特性——集群。本文主要內容包括集群搭建、集群分區原理和集群操作的學習。

回到頂部

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安裝目錄的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將數據均勻分布到各個節點上的基礎。

鍵-槽-節點(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

(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)了。從新分配完後再次查看集群節點信息

可見,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

再來查看集群節點信息

可見,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

redis高級應用(集群搭建、集群分區原理、集群操作)