標籤:
Redis Cluster終於出了Stable,這讓人很是激動,等Stable很久了,所以還是先玩玩。
一. 叢集簡單概念。
Redis 叢集是一個可以在多個 Redis 節點之間進行資料共用的設施(installation)。
Redis 叢集不支援那些需要同時處理多個鍵的 Redis 命令, 因為執行這些命令需要在多個 Redis 節點之間移動資料, 並且在高負載的情況下, 這些命令將降低 Redis 叢集的效能, 並導致不可預測的行為。
Redis 叢集通過分區(partition)來提供一定程度的可用性(availability): 即使叢集中有一部分節點失效或者無法進行通訊, 叢集也可以繼續處理命令請求。
Redis 叢集提供了以下兩個好處:
- 將資料自動切分(split)到多個節點的能力。
- 當叢集中的一部分節點失效或者無法進行通訊時, 仍然可以繼續處理命令請求的能力。
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 就可以了。
因為將一個雜湊槽從一個節點移動到另一個節點不會造成節點阻塞, 所以無論是添加新節點還是移除已存在節點, 又或者改變某個節點包含的雜湊槽數量, 都不會造成叢集下線。
為了使得叢集在一部分節點下線或者無法與叢集的大多數(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.0make && make install
3.建立存放多個執行個體的目錄
mkdir /data/cluster -pcd /data/clustermkdir 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/7000redis-server redis.confcd /data/cluster/7001redis-server redis.confcd /data/cluster/7002redis-server redis.confcd /data/cluster/7003redis-server redis.confcd /data/cluster/7004redis-server redis.confcd /data/cluster/7005redis-server redis.conf
查看進程否存在。
[[email protected] 7005]# ps -ef | grep redisroot 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 clusterConnecting to node 127.0.0.1:7000: OKConnecting to node 127.0.0.1:7001: OKConnecting to node 127.0.0.1:7002: OKConnecting to node 127.0.0.1:7003: OKConnecting to node 127.0.0.1:7004: OKConnecting to node 127.0.0.1:7005: OK>>> Performing hash slots allocation on 6 nodes...Using 3 masters:127.0.0.1:7000127.0.0.1:7001127.0.0.1:7002Adding replica 127.0.0.1:7003 to 127.0.0.1:7000Adding replica 127.0.0.1:7004 to 127.0.0.1:7001Adding replica 127.0.0.1:7005 to 127.0.0.1:7002M: 2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000 slots:0-5460 (5461 slots) masterM: 2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001 slots:5461-10922 (5462 slots) masterM: 0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002 slots:10923-16383 (5461 slots) masterS: 37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003 replicates 2774f156af482b4f76a5c0bda8ec561a8a1719c2S: e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004 replicates 2d03b862083ee1b1785dba5db2987739cf3a80ebS: 9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005 replicates 0456869a2c2359c3e06e065a09de86df2e3135acCan 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 clusterWaiting 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) masterM: 2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001 slots:5461-10922 (5462 slots) masterM: 0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002 slots:10923-16383 (5461 slots) masterM: 37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003 slots: (0 slots) master replicates 2774f156af482b4f76a5c0bda8ec561a8a1719c2M: e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004 slots: (0 slots) master replicates 2d03b862083ee1b1785dba5db2987739cf3a80ebM: 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 或者 redis-cli , 接下來我們將使用 redis-cli 為例來進行示範:
[[email protected] ~]# redis-cli -c -p 7001127.0.0.1:7001> set name yayunOK127.0.0.1:7001> get name"yayun"127.0.0.1:7001>
我們可以看看還有哪些命令可以用:
[[email protected] ~]# redis-trib helpUsage: 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.[[email protected] ~]#
可以看見有add-node,不用想了,肯定是添加節點。那麼del-node就是刪除節點。還有check肯定就是檢查狀態了。
[[email protected] ~]# redis-cli -p 7000 cluster nodes 2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001 master - 0 1428293673322 2 connected 5461-1092237b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003 slave 2774f156af482b4f76a5c0bda8ec561a8a1719c2 0 1428293672305 4 connectede2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004 slave 2d03b862083ee1b1785dba5db2987739cf3a80eb 0 1428293674340 5 connected0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002 master - 0 1428293670262 3 connected 10923-163832774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000 myself,master - 0 0 1 connected 0-54609923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005 slave 0456869a2c2359c3e06e065a09de86df2e3135ac 0 1428293675362 6 connected[[email protected] ~]#
可以看到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執行個體,再進行查詢。
[[email protected] ~]# ps -ef | grep 7000root 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[[email protected] ~]# kill 4168[[email protected] ~]# ps -ef | grep 7000root 4387 4361 0 12:39 pts/3 00:00:00 grep 7000[[email protected] ~]# redis-cli -c -p 7001127.0.0.1:7001> get name"yayun"127.0.0.1:7001>
可以正常擷取到value,現在看看狀態。
[[email protected] ~]# redis-cli -c -p 7001 cluster nodes2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001 myself,master - 0 0 2 connected 5461-109220456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002 master - 0 1428295271619 3 connected 10923-1638337b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003 master - 0 1428295270603 7 connected 0-5460e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004 slave 2d03b862083ee1b1785dba5db2987739cf3a80eb 0 1428295272642 5 connected2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000 master,fail - 1428295159553 1428295157205 1 disconnected9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005 slave 0456869a2c2359c3e06e065a09de86df2e3135ac 0 1428295269587 6 connected[[email protected] ~]#
原來的7000連接埠執行個體已經顯示fail,原來的7003是slave,現在自動提升為master。
關於更多的線上添加節點,刪除節點,以及對叢集進行重新分區請參考官方文檔。
總結:
redis-cluster是個好東西,只是stable才出來不久,肯定坑略多,而且現在使用的人比較少,前期瞭解學習一下是可以的,生產環境肯定要謹慎考慮。且需要進行嚴格的測試。生產環境中redis的叢集可以考慮使用Twitter開源的twemproxy,以及豌豆莢開源的codis,這兩個項目都比較成熟,現在使用的公司很多。已經向業界朋友得到證實。後面也會寫部落格介紹twemproxy和codis。
Redis叢集環境的部署記錄