Redis Cluster 3.0搭建與使用


    最近redis已經比較火了,有關redis的詳細介紹,網上有一大堆,我這里只作簡單的介紹,然后跟大家一起學習Redis Cluster 3.0的搭建與使用。Redis是一款開源的、網絡化的、基於內存的、可進行數據持久化的Key-Value存儲系統。它的數據模型建立在外層,類似於其它結構化存儲系統,是通過Key映射Value的方式來建立字典以保存數據,有別於其它結構化存儲系統的是,它支持多類型存儲,包括String、List、Set、Sort set和Hash等,你可以在這些數據類型上做很多原子性操作,比如使用Push/Pop/Add/Remove、交並集、差集等,同時在此基礎之上可以支持不同方式的排序。

    reids-cluster計划在redis3.0中推出,相信很多小伙伴們聽到都有點小雞動吧,哈哈,下面我們一起來玩玩reids-cluster

一、Redis集群介紹

    1)Redis集群是一個可以在多個Redis節點之間進行數據共享的設施(installation)。

    2)Redis集群不支持那些需要同時處理多個鍵的Redis命令,因為執行這些命令需要在多個Redis節點之間移動數據,並且在高負載的情況下,這些命令將降低Redis集群的性能,並導致不可預測的行為。

    3)Redis集群通過分區(partition)來提供一定程度的可用性(availability):即使集群中有一部份分節點失效或者無法進行通訊,集群也可以繼續處理命令請求。

Redis集群提供了以下兩個好處

    1、將數據自動切分(split)到多個節點的能力。

    2、當集群中的一部份節點失效或者無法進行通訊時,仍然可以繼續處理命令請求的能力。

 

二、Redis集群數據共享

Redis集群使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現:一個Redis集群包含16384個哈希槽(hash slot),數據庫中的每個鍵都屬於這個16384個哈希槽的其中一個,集群使用公式CRC16(key) % 16384來計算鍵key屬於哪個槽,其中CRC16(key)語句用於計算鍵key的CRC16校驗和。

集群中的每個節點負責處理一部分哈希槽。舉個例子,一個集群有三個哈希槽,其中:

     節點 A 負責處理0號至於5500號哈希槽。

     節點 B 負責處理5501號至11000號哈希槽。

     節點 C 負責處理11001號至16384號哈希槽。

這種將哈希槽分布到不同節點的做法使得用戶可以很容易地向集群中添加或者刪除節點。比如說:

  • 如果用戶將新節點 D 添加到集群中, 那么集群只需要將節點 A 、B 、 C 中的某些槽移動到節點 D 就可以了。
  • 與此類似, 如果用戶要從集群中移除節點 A , 那么集群只需要將節點 A 中的所有哈希槽移動到節點 B 和節點 C , 然后再移除空白(不包含任何哈希槽)的節點 A 就可以了。

 因為將一個哈希槽從一個節點移動到另一個節點不會造成節點阻塞,所以無論是添加新節點還是移除已經存在的節點,又或者改變某個節點包含的哈希數量,都不會造成集群下線。

 

三、Redis集群中的主從復制

為了使得集群在一部分節點下線或者無法與集群的大多數(majority)節點進行通訊的情況下, 仍然可以正常運作,Redis 集群對節點使用了主從復制功能: 集群中的每個節點都有 1 個至 N 個復制品(replica), 其中一個復制品為主節點(master), 而其余的 N-1 個復制品為從節點(slave)。

在之前列舉的節點 A 、B 、C 的例子中, 如果節點 B 下線了, 那么集群將無法正常運行, 因為集群找不到節點來處理 5501 號至 11000 號的哈希槽。

另一方面, 假如在創建集群的時候(或者至少在節點 B 下線之前), 我們為主節點 B 添加了從節點 B1 , 那么當主節點 B 下線的時候, 集群就會將 B1 設置為新的主節點, 並讓它代替下線的主節點 B , 繼續處理 5501 號至 11000 號的哈希槽, 這樣集群就不會因為主節點 B 的下線而無法正常運作了。

不過如果節點 B 和 B1 都下線的話,Redis 集群還是會停止運作。

1)redis-cluster架構圖:

架構細節:

(1)所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.

(2)節點的fail是通過集群中超過半數的節點檢測失效時才生效.

(3)客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可

(4)redis-cluster把所有的物理節點映射到[0-16383]slot上,cluster 負責維護node<->slot<->value

2.redis-cluster選舉:容錯圖:

 

(1)領着選舉過程是集群中所有master參與,如果半數以上master節點與master節點通信超過(cluster-node-timeout),認為當前master節點掛掉。

(2):什么時候整個集群不可用(cluster_state:fail)?

    a:如果集群任意master掛掉,且當前master沒有slave.集群進入fail狀態,也可以理解成集群的slot映射[0-16383]不完成時進入fail狀態。 (redis-3.0.0.rc1加入cluster-require-full-coverage參數,默認關閉,打開集群兼容部分失敗。)

    b:如果集群超過半數以上master掛掉,無論是否有slave集群進入fail狀態。(當集群不可用時,所有對集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)錯誤)

 

四、Redis Cluster搭建使用

要讓集群正常運作至少需要三個主節點, 不過在剛開始試用集群功能時, 強烈建議使用六個節點: 其中三個為主節點, 而其余三個則是各個主節點的從節點:(為了方便,我只有一台機子演示),分別是:

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

1、下載軟件包:

[root ~]$ wget http://download.redis.io/releases/redis-3.0.0.tar.gz

2. 解壓,安裝

[root ~]$ tar xf redis-3.0.0.tar.gz 
[root ~]$ cd redis-3.0.0
[root redis-3.0.0]$ make && make install

3.創建存放多個實例的目錄

[root redis-3.0.0]$ mkdir /data/cluster -p
[root redis-3.0.0]$ cd /data/cluster
[root cluster]$ mkdir 7000 7001 7002 7003 7004 7005

4.修改配置文件

[root redis-3.0.0]$ pwd
/root/redis-3.0.0
[root redis-3.0.0]$ cp redis.conf /data/cluster/7000/

修改配置文件中下面選項

port 7000

daemonize yes

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

選項簡單介紹:

   cluster-enabled:用於開實例的集群模式

   cluster-conf-file:選項則設定了保存節點配置文件的路徑,默認值為nodes.conf

節點配置文件無須人為修改, 它由 Redis 集群在啟動時創建, 並在有需要時自動進行更新

修改完成后,把修改好的redis.conf復制到7001-7005目錄下,並修改其端口

[root 7000]$ cp redis.conf /data/cluster/7001/
[root 7000]$ cp redis.conf /data/cluster/7002/
[root 7000]$ cp redis.conf /data/cluster/7003/
[root 7000]$ cp redis.conf /data/cluster/7004/
[root 7000]$ cp redis.conf /data/cluster/7005/
[root 7000]$ sed -i "s#7000#7001#g" /data/cluster/7001/redis.conf 
[root 7000]$ sed -i "s#7000#7002#g" /data/cluster/7002/redis.conf   
[root 7000]$ sed -i "s#7000#7003#g" /data/cluster/7003/redis.conf   
[root 7000]$ sed -i "s#7000#7004#g" /data/cluster/7004/redis.conf   
[root 7000]$ sed -i "s#7000#7005#g" /data/cluster/7005/redis.conf

5.分別啟動6個redis實例。

[root ~]$ cd /data/cluster/7000
[root 7000]$ redis-server redis.conf

[root
7000]$ cd /data/cluster/7001 [root 7001]$ redis-server redis.conf
[root
7001]$ cd /data/cluster/7002 [root 7002]$ redis-server redis.conf
[root
7002]$ cd /data/cluster/7003 [root 7003]$ redis-server redis.conf
[root
7003]$ cd /data/cluster/7004 [root 7004]$ redis-server redis.conf
[root
7004]$ cd /data/cluster/7005 [root 7005]$ redis-server redis.conf

查看進程是否都正常啟動了:

[root 7005]$ ps -ef | grep redis
 root     16403     1  0 01:38 ?        00:00:00 redis-server *:7000 [cluster]
 root     16408     1  0 01:39 ?        00:00:00 redis-server *:7001 [cluster]
 root     16412     1  0 01:39 ?        00:00:00 redis-server *:7002 [cluster]
 root     16416     1  0 01:39 ?        00:00:00 redis-server *:7003 [cluster]
 root     16420     1  0 01:39 ?        00:00:00 redis-server *:7004 [cluster]
 root     16424     1  0 01:40 ?        00:00:00 redis-server *:7005 [cluster]
 root     16428  9516  0 01:43 pts/0    00:00:00 grep redis
[root
7005]$

6.執行命令創建集群,首先安裝依賴,否則創建集群失敗。

[root ~]$ yum install ruby rubygems -y

安裝gem-redis

下載地址:https://rubygems.org/gems/redis/versions/3.0.0

[root ~]$ gem install -l redis-3.0.0.gem 
Successfully installed redis-3.0.0
1 gem installed
Installing ri documentation for redis-3.0.0...
Installing RDoc documentation for redis-3.0.0...

復制集群管理程序到/usr/local/bin

[root ~]$ cp redis-3.0.0/src/redis-trib.rb /usr/local/bin/redis-trib

創建集群:

[root ~]$ redis-trib 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

命令的意義如下:

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

簡單來說, 以上命令的意思就是讓 redis-trib 程序創建一個包含三個主節點和三個從節點的集群。

如果配置都OK,會打印如下信息,然后你覺得OK,沒問題后,就可以輸入yes

>>> 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: d8a0120620d3563623190ba214a9c717f19b66c0 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: ef3361880fa6f88a27415a8f57d7c6dfd848b500 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: a33e7add3a1561ebd740c910e538cd1debde0aee 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
S: c48d68f0c44a2e242b5695909aee629005c1da60 127.0.0.1:7003
   replicates d8a0120620d3563623190ba214a9c717f19b66c0
S: 7bf071948c90ab64e650a7a76347f25556350336 127.0.0.1:7004
   replicates ef3361880fa6f88a27415a8f57d7c6dfd848b500
S: 873a82deae732b73b9377e992174a7d52db9fcc9 127.0.0.1:7005
   replicates a33e7add3a1561ebd740c910e538cd1debde0aee
Can I set the above configuration? (type 'yes' to accept): yes
>>> 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 127.0.0.1:7000)
M: d8a0120620d3563623190ba214a9c717f19b66c0 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: ef3361880fa6f88a27415a8f57d7c6dfd848b500 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: a33e7add3a1561ebd740c910e538cd1debde0aee 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
M: c48d68f0c44a2e242b5695909aee629005c1da60 127.0.0.1:7003
   slots: (0 slots) master
   replicates d8a0120620d3563623190ba214a9c717f19b66c0
M: 7bf071948c90ab64e650a7a76347f25556350336 127.0.0.1:7004
   slots: (0 slots) master
   replicates ef3361880fa6f88a27415a8f57d7c6dfd848b500
M: 873a82deae732b73b9377e992174a7d52db9fcc9 127.0.0.1:7005
   slots: (0 slots) master
   replicates a33e7add3a1561ebd740c910e538cd1debde0aee
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

輸入 yes 並按下回車確認之后, 集群就會將配置應用到各個節點, 並連接起(join)各個節點 ——也即是, 讓各個節點開始互相通訊,一切正常輸出的信息如下:

[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.


五、集群客戶端

Redis 集群現階段的一個問題是客戶端實現很少。 以下是一些我知道的實現:

  • redis-rb-cluster 是我(@antirez)編寫的 Ruby 實現, 用於作為其他實現的參考。 該實現是對 redis-rb 的一個簡單包裝, 高效地實現了與集群進行通訊所需的最少語義(semantic)。
  • redis-py-cluster 看上去是 redis-rb-cluster 的一個 Python 版本, 這個項目有一段時間沒有更新了(最后一次提交是在六個月之前), 不過可以將這個項目用作學習集群的起點。
  • 流行的 Predis 曾經對早期的 Redis 集群有過一定的支持, 但我不確定它對集群的支持是否完整, 也不清楚它是否和最新版本的 Redis 集群兼容 (因為新版的 Redis 集群將槽的數量從 4k 改為 16k 了)。
  • Redis unstable 分支中的 redis-cli 程序實現了非常基本的集群支持, 可以使用命令 redis-cli -c 來啟動。

測試 Redis 集群比較簡單的辦法就是使用 redis-rb-cluster 或者 redis-cli , 接下來我們將使用 redis-cli 為例來進行演示:

[root ~]$ redis-cli -c -p 7001
127.0.0.1:7001> set name test
OK
127.0.0.1:7001> set user root
OK
-> Redirected to slot [741] located at 127.0.0.1:7000 OK 127.0.0.1:7000> get name -> Redirected to slot [5798] located at 127.0.0.1:7001 "test" 127.0.0.1:7000>

我們可以看看還有哪些命令可以用:

[root ~]$ redis-trib help
Usage: redis-trib <command> <options> <arguments ...>

  help            (show this help)
  set-timeout     host:port milliseconds
  del-node        host:port node_id
  import          host:port
                  --from <arg>
  add-node        new_host:new_port existing_host:existing_port
                  --master-id <arg>
                  --slave
  reshard         host:port
                  --to <arg>
                  --from <arg>
                  --slots <arg>
                  --yes
  check           host:port
  call            host:port command arg arg .. arg
  create          host1:port1 ... hostN:portN
                  --replicas <arg>
  fix             host:port

For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.

 按字面意思,相信大家都能看懂,add-node添加節點,del-node刪除節點,check檢查節點,set-timeout設置超時時間,意思是多久沒返回狀態,就認為它掛了。

[root ~]$ redis-cli -p 7000 cluster nodes 
d8a0120620d3563623190ba214a9c717f19b66c0 127.0.0.1:7000 myself,master - 0 0 1 connected 0-5460
7bf071948c90ab64e650a7a76347f25556350336 127.0.0.1:7004 slave ef3361880fa6f88a27415a8f57d7c6dfd848b500 0 1428476589001 5 connected
873a82deae732b73b9377e992174a7d52db9fcc9 127.0.0.1:7005 slave a33e7add3a1561ebd740c910e538cd1debde0aee 0 1428476587997 6 connected
a33e7add3a1561ebd740c910e538cd1debde0aee 127.0.0.1:7002 master - 0 1428476581989 3 connected 10923-16383
c48d68f0c44a2e242b5695909aee629005c1da60 127.0.0.1:7003 slave d8a0120620d3563623190ba214a9c717f19b66c0 0 1428476585992 4 connected
ef3361880fa6f88a27415a8f57d7c6dfd848b500 127.0.0.1:7001 master - 0 1428476586995 2 connected 5461-10922
[root ~]$

可以看到7000、7001、7002是master,7003-7005是slave,同時也可以看到每個master管理的哈希槽,7000管理的哈希槽是0-5460,7001管理的哈希槽是5461-10922,7002管理的哈希槽是10923-16383

六、故障轉移測試:

127.0.0.1:7001> KEYS *
1) "user"
2) "name"
127.0.0.1:7001> 

模擬master節點7001掛了:

[root ~]$ ps -ef | grep 7001
root     16408     1  0 01:39 ?        00:00:04 redis-server *:7001 [cluster]
root     18743  9516  0 15:19 pts/0    00:00:00 grep 7001
[root ~]$ kill -9 16408

查看一下新的master轉移到那個節點上了:

[root ~]$ redis-cli -c -p 7000 cluster nodes 
d8a0120620d3563623190ba214a9c717f19b66c0 127.0.0.1:7000 myself,master - 0 0 1 connected 0-5460
7bf071948c90ab64e650a7a76347f25556350336 127.0.0.1:7004 master - 0 1428477751718 7 connected 5461-10922
873a82deae732b73b9377e992174a7d52db9fcc9 127.0.0.1:7005 slave a33e7add3a1561ebd740c910e538cd1debde0aee 0 1428477755719 6 connected
a33e7add3a1561ebd740c910e538cd1debde0aee 127.0.0.1:7002 master - 0 1428477754719 3 connected 10923-16383
c48d68f0c44a2e242b5695909aee629005c1da60 127.0.0.1:7003 slave d8a0120620d3563623190ba214a9c717f19b66c0 0 1428477749716 4 connected
ef3361880fa6f88a27415a8f57d7c6dfd848b500 127.0.0.1:7001 master,fail - 1428477608909 1428477606404 2 disconnected

可以看到7001 master,fail,原來的7004是slave,現在自動提升為master,測試一下取值:

[root ~]$ redis-cli -c -p 7004
127.0.0.1:7004> keys *
1) "user"
2) "name"
127.0.0.1:7004> get name
"test"
127.0.0.1:7004> get user
"root"
127.0.0.1:7004> 

依然正常獲取鍵值。
同理,在7000里設置幾個鍵值,然后kill掉7000節點:

127.0.0.1:7000> keys *
1) "aa"
2) "age"
127.0.0.1:7000> 
[root ~]$ ps -ef | grep 7000
 root     16403     1  0 01:38 ?        00:00:04 redis-server *:7000 [cluster]
 root     18775  9516  0 15:34 pts/0    00:00:00 grep 7000
[root ~]$ kill -9 16403

然后查一下,可以發現7003提升為master了,其實對應關系是7000(master)->7003(slave),7001(master)->7004(slave),7002(master)->7005(slave),當master死掉,會自動把slave提升為master

[root ~]$ redis-cli -c -p 7002 cluster nodes
873a82deae732b73b9377e992174a7d52db9fcc9 127.0.0.1:7005 slave a33e7add3a1561ebd740c910e538cd1debde0aee 0 1428478631146 6 connected
c48d68f0c44a2e242b5695909aee629005c1da60 127.0.0.1:7003 master - 0 1428478630145 8 connected 0-5460
a33e7add3a1561ebd740c910e538cd1debde0aee 127.0.0.1:7002 myself,master - 0 0 3 connected 10923-16383
ef3361880fa6f88a27415a8f57d7c6dfd848b500 127.0.0.1:7001 master,fail - 1428477609001 1428477607099 2 disconnected
d8a0120620d3563623190ba214a9c717f19b66c0 127.0.0.1:7000 master,fail - 1428478495767 1428478491866 1 disconnected
7bf071948c90ab64e650a7a76347f25556350336 127.0.0.1:7004 master - 0 1428478632146 7 connected 5461-10922

登錄7003節點測試下:

[root ~]$ redis-cli -c -p 7003
127.0.0.1:7003> keys *
1) "aa"
2) "age"
127.0.0.1:7003> get age
"24"
127.0.0.1:7003> get aa
"abc"
127.0.0.1:7003> 

還是正常的。
接着我們測試下,如果剛剛從slave節點升為master節點的節點也掛了,集群還能不能正常工作呢?我們把7004 kill掉:

[root ~]$ ps -ef | grep 7004
 root     16420     1  0 01:39 ?        00:00:04 redis-server *:7004 [cluster]
 root     18785  9516  0 15:44 pts/0    00:00:00 grep 7004
[root ~]$ kill -9 16420

檢查一下有沒有新的節點代替7004成為新的master:

[root ~]$ redis-cli -c -p 7002 cluster nodes
873a82deae732b73b9377e992174a7d52db9fcc9 127.0.0.1:7005 slave a33e7add3a1561ebd740c910e538cd1debde0aee 0 1428479109253 6 connected
c48d68f0c44a2e242b5695909aee629005c1da60 127.0.0.1:7003 master - 0 1428479108253 8 connected 0-5460
a33e7add3a1561ebd740c910e538cd1debde0aee 127.0.0.1:7002 myself,master - 0 0 3 connected 10923-16383
ef3361880fa6f88a27415a8f57d7c6dfd848b500 127.0.0.1:7001 master,fail - 1428477609001 1428477607099 2 disconnected
d8a0120620d3563623190ba214a9c717f19b66c0 127.0.0.1:7000 master,fail - 1428478495767 1428478491866 1 disconnected
7bf071948c90ab64e650a7a76347f25556350336 127.0.0.1:7004 master,fail - 1428479059546 1428479058145 7 disconnected 5461-10922
[root ~]$ 

可以看到7005還是slave,沒有提升為master。所以當master節點和候選master節點都掛了,整個集群都將會無法再正常工作。我們登錄還活着的master 7003驗證下:

[root ~]$ redis-cli -c -p 7003
127.0.0.1:7003> keys *
1) "aa"
2) "age"
127.0.0.1:7003> get aa
(error) CLUSTERDOWN The cluster is down 127.0.0.1:7003> 

可以看到The cluster is down,這集群已經down了,說明集群已經不可用了
關於更多的在線添加節點,刪除節點,以及對集群進行重新分片請參考官方文檔。

 

總結:

一、redis-cluster是個好東西,而且配置非常簡單,當master節點掛了后,slave會自動提升為master,還是挺不錯的

二、由於redis-cluster才剛剛出來不久,而且現在使用的人比較少,如果想在生產環境搭建,要慎重考慮,需要進行嚴格的測試,不過相信它會慢慢強大起來的。

三、現在比較成熟redis的集群可以考慮使用Twitter開源的twemproxy,以及豌豆莢開源的codis,這兩個項目都比較成熟,現在使用的公司很多

 

參考資料:

http://redis.readthedocs.org/en/latest/topic/cluster-tutorial.html

http://hot66hot.iteye.com/blog/2050676

http://www.cnblogs.com/gomysql/p/4395504.html

 

作者:陸炫志

出處:xuanzhi的博客 http://www.cnblogs.com/xuanzhi201111

您的支持是對博主最大的鼓勵,感謝您的認真閱讀。本文版權歸作者所有,歡迎轉載,但請保留該聲明。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM