Redis Cluster 3.0搭建與使用

Redis Cluster終於出了Stable,這讓人非常激動,等Stable好久了,因此仍是先玩玩。html

一. 集羣簡單概念。node

Redis 集羣是一個能夠在多個 Redis 節點之間進行數據共享的設施(installation)。git

Redis 集羣不支持那些須要同時處理多個鍵的 Redis 命令, 由於執行這些命令須要在多個 Redis 節點之間移動數據, 而且在高負載的狀況下, 這些命令將下降 Redis 集羣的性能, 並致使不可預測的行爲。github

Redis 集羣經過分區(partition)來提供必定程度的可用性(availability): 即便集羣中有一部分節點失效或者沒法進行通信, 集羣也能夠繼續處理命令請求。redis

Redis 集羣提供瞭如下兩個好處:數據庫

  • 將數據自動切分(split)到多個節點的能力。
  • 當集羣中的一部分節點失效或者沒法進行通信時, 仍然能夠繼續處理命令請求的能力。

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

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

  • 節點 A 負責處理 0 號至 5500 號哈希槽。
  • 節點 B 負責處理 5501 號至 11000 號哈希槽。
  • 節點 C 負責處理 11001 號至 16384 號哈希槽。

這種將哈希槽分佈到不一樣節點的作法使得用戶能夠很容易地向集羣中添加或者刪除節點。 好比說:app

  • 若是用戶將新節點 D 添加到集羣中, 那麼集羣只須要將節點 A 、B 、 C 中的某些槽移動到節點 D 就能夠了。
  • 與此相似, 若是用戶要從集羣中移除節點 A , 那麼集羣只須要將節點 A 中的全部哈希槽移動到節點 B 和節點 C , 而後再移除空白(不包含任何哈希槽)的節點 A 就能夠了。

由於將一個哈希槽從一個節點移動到另外一個節點不會形成節點阻塞, 因此不管是添加新節點仍是移除已存在節點, 又或者改變某個節點包含的哈希槽數量, 都不會形成集羣下線。性能

爲了使得集羣在一部分節點下線或者沒法與集羣的大多數(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 集羣仍是會中止運做。

Redis-cluster 架構圖以下:

 

架構細節:

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

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

(3)客戶端與redis節點直連,不須要中間proxy層.客戶端不須要鏈接集羣全部節點,鏈接集羣中任何一個可用節點便可

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

 

二. Redis Cluster搭建使用

要讓集羣正常工做至少須要3個主節點,在這裏咱們要建立6個redis節點,其中三個爲主節點,三個爲從節點,對應的redis節點的ip和端口對應關係以下(爲了簡單演示都在同一臺機器上面)

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. 下載最新版redis。

wget http://download.redis.io/releases/redis-3.0.0.tar.gz

2. 解壓,安裝

tar xf redis-3.0.0.tar.gz                       
cd redis-3.0.0
make && make install

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

mkdir /data/cluster -p
cd /data/cluster
mkdir 7000 7001 7002 7003 7004 7005

4.修改配置文件

cp redis-3.0.0/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目錄下,而且端口修改爲和文件夾對應。

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

cd /data/cluster/7000
redis-server redis.conf
cd /data/cluster/7001
redis-server redis.conf
cd /data/cluster/7002
redis-server redis.conf
cd /data/cluster/7003
redis-server redis.conf
cd /data/cluster/7004
redis-server redis.conf
cd /data/cluster/7005
redis-server redis.conf

查看進程否存在。

[root@redis-server 7005]# ps -ef | grep redis
root      4168     1  0 11:49 ?        00:00:00 redis-server *:7000 [cluster]
root      4176     1  0 11:49 ?        00:00:00 redis-server *:7001 [cluster]
root      4186     1  0 11:50 ?        00:00:00 redis-server *:7002 [cluster]
root      4194     1  0 11:50 ?        00:00:00 redis-server *:7003 [cluster]
root      4202     1  0 11:50 ?        00:00:00 redis-server *:7004 [cluster]
root      4210     1  0 11:50 ?        00:00:00 redis-server *:7005 [cluster]
root      4219  4075  0 11:50 pts/2    00:00:00 grep redis

6.執行命令建立集羣,首先安裝依賴,不然建立集羣失敗。

yum install ruby rubygems -y

安裝gem-redis

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

gem install -l redis-3.0.0.gem  

複製集羣管理程序到/usr/local/bin

cp redis-3.0.0/src/redis-trib.rb /usr/local/bin/redis-trib 

建立集羣:

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 程序建立一個包含三個主節點和三個從節點的集羣。

接着, redis-trib 會打印出一份預想中的配置給你看, 若是你以爲沒問題的話, 就能夠輸入 yes , redis-trib 就會將這份配置應用到集羣當中:

>>> 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: 2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: 2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: 0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
S: 37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003
   replicates 2774f156af482b4f76a5c0bda8ec561a8a1719c2
S: e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004
   replicates 2d03b862083ee1b1785dba5db2987739cf3a80eb
S: 9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005
   replicates 0456869a2c2359c3e06e065a09de86df2e3135ac
Can I set the above configuration? (type 'yes' to accept): 

輸入 yes 並按下回車確認以後, 集羣就會將配置應用到各個節點, 並鏈接起(join)各個節點 —— 也便是, 讓各個節點開始互相通信:

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: 2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: 2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: 0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
M: 37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003
   slots: (0 slots) master
   replicates 2774f156af482b4f76a5c0bda8ec561a8a1719c2
M: e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004
   slots: (0 slots) master
   replicates 2d03b862083ee1b1785dba5db2987739cf3a80eb
M: 9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005
   slots: (0 slots) master
   replicates 0456869a2c2359c3e06e065a09de86df2e3135ac
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

一切正常輸出如下信息:

[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-server ~]# redis-cli -c -p 7001
127.0.0.1:7001> set name yayun
OK
127.0.0.1:7001> get name
"yayun"
127.0.0.1:7001> 

咱們能夠看看還有哪些命令能夠用:

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

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

For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.
[root@redis-server ~]# 

能夠看見有add-node,不用想了,確定是添加節點。那麼del-node就是刪除節點。還有check確定就是檢查狀態了。

[root@redis-server ~]#  redis-cli -p 7000 cluster nodes 
2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001 master - 0 1428293673322 2 connected 5461-10922
37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003 slave 2774f156af482b4f76a5c0bda8ec561a8a1719c2 0 1428293672305 4 connected
e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004 slave 2d03b862083ee1b1785dba5db2987739cf3a80eb 0 1428293674340 5 connected
0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002 master - 0 1428293670262 3 connected 10923-16383
2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000 myself,master - 0 0 1 connected 0-5460
9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005 slave 0456869a2c2359c3e06e065a09de86df2e3135ac 0 1428293675362 6 connected
[root@redis-server ~]# 

能夠看到7000-7002是master,7003-7005是slave。

故障轉移測試:

127.0.0.1:7001> KEYS *
1) "name"
127.0.0.1:7001> get name
"yayun"
127.0.0.1:7001> 

能夠看見7001是正常的,而且獲取到了key,value,如今kill掉7000實例,再進行查詢。

[root@redis-server ~]# ps -ef | grep 7000
root      4168     1  0 11:49 ?        00:00:03 redis-server *:7000 [cluster]
root      4385  4361  0 12:39 pts/3    00:00:00 grep 7000
[root@redis-server ~]# kill 4168
[root@redis-server ~]# ps -ef | grep 7000
root      4387  4361  0 12:39 pts/3    00:00:00 grep 7000
[root@redis-server ~]# redis-cli -c -p 7001
127.0.0.1:7001> get name
"yayun"
127.0.0.1:7001> 

能夠正常獲取到value,如今看看狀態。

[root@redis-server ~]# redis-cli -c -p 7001 cluster nodes
2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001 myself,master - 0 0 2 connected 5461-10922
0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002 master - 0 1428295271619 3 connected 10923-16383
37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003 master - 0 1428295270603 7 connected 0-5460
e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004 slave 2d03b862083ee1b1785dba5db2987739cf3a80eb 0 1428295272642 5 connected
2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000 master,fail - 1428295159553 1428295157205 1 disconnected 9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005 slave 0456869a2c2359c3e06e065a09de86df2e3135ac 0 1428295269587 6 connected
[root@redis-server ~]# 

原來的7000端口實例已經顯示fail,原來的7003是slave,如今自動提高爲master。

關於更多的在線添加節點,刪除節點,以及對集羣進行從新分片請參考官方文檔。

總結:

redis-cluster是個好東西,只是stable纔出來不久,確定坑略多,並且如今使用的人比較少,前期瞭解學習一下是能夠的,生產環境確定要慎重考慮。且須要進行嚴格的測試。生產環境中redis的集羣能夠考慮使用Twitter開源的twemproxy,以及豌豆莢開源的codis,這兩個項目都比較成熟,如今使用的公司不少。已經向業界朋友獲得證明。後面也會寫博客介紹twemproxy和codis。

參考資料:

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

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

相關文章
相關標籤/搜索