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