Redis Cluster終於出了Stable,這讓人非常激動,等Stable好久了,因此仍是先玩玩。html
一. 集羣簡單概念。node
Redis 集羣是一個能夠在多個 Redis 節點之間進行數據共享的設施(installation)。git
Redis 集羣不支持那些須要同時處理多個鍵的 Redis 命令, 由於執行這些命令須要在多個 Redis 節點之間移動數據, 而且在高負載的狀況下, 這些命令將下降 Redis 集羣的性能, 並致使不可預測的行爲。github
Redis 集羣經過分區(partition)來提供必定程度的可用性(availability): 即便集羣中有一部分節點失效或者沒法進行通信, 集羣也能夠繼續處理命令請求。redis
Redis 集羣提供瞭如下兩個好處:數據庫
Redis 集羣使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現: 一個 Redis 集羣包含 16384 個哈希槽(hash slot), 數據庫中的每一個鍵都屬於這 16384 個哈希槽的其中一個, 集羣使用公式 CRC16(key) % 16384 來計算鍵 key 屬於哪一個槽, 其中 CRC16(key) 語句用於計算鍵 key 的 CRC16 校驗和 。ruby
集羣中的每一個節點負責處理一部分哈希槽。 舉個例子, 一個集羣能夠有三個哈希槽, 其中:架構
這種將哈希槽分佈到不一樣節點的作法使得用戶能夠很容易地向集羣中添加或者刪除節點。 好比說:app
由於將一個哈希槽從一個節點移動到另外一個節點不會形成節點阻塞, 因此不管是添加新節點仍是移除已存在節點, 又或者改變某個節點包含的哈希槽數量, 都不會形成集羣下線。性能
爲了使得集羣在一部分節點下線或者沒法與集羣的大多數(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 程序建立一個包含三個主節點和三個從節點的集羣。
接着, 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 集羣比較簡單的辦法就是使用 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