1:redis cluster的現狀
目前redis支持的cluster特性(已親測): 1):節點自動發現
2):slave->master 選舉,集羣容錯 3):Hot resharding:在線分片 4):進羣管理:cluster xxx
5):基於配置(nodes-port.conf)的集羣管理 6):ASK 轉向/MOVED 轉向機制.
2:redis cluster 架構 1)redis-cluster架構圖node
架構細節:
(1)全部的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.
(2)節點的fail是經過集羣中超過半數的節點檢測失效時才生效.
(3)客戶端與redis節點直連,不須要中間proxy層.客戶端不須要鏈接集羣全部節點,鏈接集羣中任何一個可用節點便可
(4)redis-cluster把全部的物理節點映射到[0-16383]slot上,cluster 負責維護node<->slot<->value 2) redis-cluster選舉:容錯linux
(1)領着選舉過程是集羣中全部master參與,若是半數以上master節點與master節點通訊超過(cluster-node-timeout),認爲當前master節點掛掉.
(2):何時整個集羣不可用(cluster_state:fail),當集羣不可用時,全部對集羣的操做作都不可用,收到((error) CLUSTERDOWN The cluster is down)錯誤 a:若是集羣任意master掛掉,且當前master沒有slave.集羣進入fail狀態,也能夠理解成進羣的slot映射[0-16383]不完成時進入fail狀態.
b:若是進羣超過半數以上master掛掉,不管是否有slave集羣進入fail狀態.
二.Redis集羣安裝篇(centos5.8 X64系統)
(要讓集羣正常工做至少須要3個主節點,在這裏咱們要建立6個redis節點,其中三個爲主節點,三個爲從節點,對應的redis節點的ip和端口對應關係以下) redis
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。
官網下載3.0.0版本,以前2.幾的版本不支持集羣模式 下載地址:http://download.redis.io/releases/redis-3.0.2.tar.gz
2:上傳服務器,解壓,編譯 tar -zxvf redis-3.0.2.tar.gz.tar.gz mv redis-3.0.2.tar.gz.tar.gz redis3.0 cd /usr/local/redis3.0 make make install
3:建立集羣須要的目錄 mkdir -p /usr/local/cluster cd /usr/local/cluster mkdir 7000 mkdir 7001 mkdir 7002 mkdir 7003 mkdir 7004 mkdir 7005 sql
4:修改配置文件redis.conf
cp /usr/local/redis3.0/redis.conf /usr.local/cluster vi redis.conf
##修改配置文件中的下面選項 port 7000 daemonize yes cluster-enabled yes
cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes
##修改完redis.conf配置文件中的這些配置項以後把這個配置文件分別拷貝到7000/7001/7002/7003/7004/7005目錄下面
cp /usr/local/cluster/redis.conf /usr/local/cluster/7000 cp /usr/local/cluster/redis.conf /usr/local/cluster/7001 cp /usr/local/cluster/redis.conf /usr/local/cluster/7002 cp /usr/local/cluster/redis.conf /usr/local/cluster/7003 cp /usr/local/cluster/redis.conf /usr/local/cluster/7004 cp /usr/local/cluster/redis.conf /usr/local/cluster/7005
##注意:拷貝完成以後要修改7001/7002/7003/7004/7005目錄下面redis.conf文件中的port參數,分別改成對應的文件夾的名稱
5:分別啓動這6個redis實例 cd /usr/local/cluster/7000 redis-server redis.conf shell
cd /usr/local/cluster/7001 redis-server redis.conf
cd /usr/local/cluster/7002 redis-server redis.conf
cd /usr/local/cluster/7003 redis-server redis.conf
cd /usr/local/cluster/7004 redis-server redis.conf
cd /usr/local/cluster/7005 redis-server redis.conf
##啓動以後使用命令查看redis的啓動狀況ps -ef|grep redis 以下顯示則說明啓動成功
# ps -ef|grep redis
root 13703 1 0 10:03 ? 00:00:00 redis-server *:7000 [cluster] root 14015 1 0 10:04 ? 00:00:00 redis-server *:7002 [cluster] root 14133 1 0 10:04 ? 00:00:00 redis-server *:7003 [cluster] root 14172 1 0 10:04 ? 00:00:00 redis-server *:7004 [cluster] root 14187 1 0 10:04 ? 00:00:00 redis-server *:7005 [cluster] root 14323 1 0 10:04 ? 00:00:00 redis-server *:7001 [cluster]
6.升級ruby 安裝gemcentos
安裝gem 須要ruby的版本在 1.8.7 以上,默認的centos5 上都是1.8.5 版本,因此首先你的升級你的ruby , rpm
-ivh
http://yum.puppetlabs.com/el/5/products/x86_64/puppetlabs-release-5-6.noarch.rpm
yum install ruby ruby-devel rubygems rpm-build
檢查 ruby 版本:
#ruby -v
ruby 1.8.7 (2013-06-27 patchlevel 374) [x86_64-linux]
是否安裝rubygems: # rpm -qa|grep ruby ruby-rdoc-1.8.7.374-2.el5 ruby-1.8.7.374-2.el5 ruby-devel-1.8.7.374-2.el5 ruby-devel-1.8.7.374-2.el5 ruby-mode-1.8.5-24.el5 ruby-irb-1.8.7.374-2.el5 ruby-libs-1.8.7.374-2.el5 ruby-libs-1.8.7.374-2.el5 rubygems-1.3.7-1.el5
7.gem 安裝redis ruby 接口 gem install redis
8:執行redis的建立集羣命令建立集羣 api
#redis-trib.rb的create子命令構建
#--replicas 則指定了爲Redis Cluster中的每一個Master節點配備幾個Slave節點
#節點角色由順序決定,先master以後是slave
建立方式:
cd /usr/local/redis3.0/src ./redis-trib.rb
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 錯誤筆記備註:
8.1執行上面的命令的時候會報錯,由於是執行的ruby的腳本,須要ruby的環境
錯誤內容:/usr/bin/env: ruby: No such file or directory
因此須要安裝ruby的環境,這裏推薦使用yum install ruby安裝 yum install ruby
8.2而後再執行第6步的建立集羣命令,還會報錯,提示缺乏rubygems組件,使用yum安裝
錯誤內容:
./redis-trib.rb:24:in `require': no such file to load -- rubygems (LoadError) from ./redis-trib.rb:24 yum install rubygems
8.3再次執行第8步的命令,還會報錯,提示不能加載redis,是由於缺乏redis和ruby的接口,使用gem 安裝 錯誤內容:
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in ruby
`gem_original_require': no such file to load -- redis (LoadError)
from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require' from ./redis-trib.rb:25
gem install redis
8.4 再次執行第8步的命令,正常執行 輸入yes,而後配置完成。服務器
注意觀察 主從的配置:
默認是前三個節點 7000 7001 7002 是主, 後3個節點 7003 7004 7005 是從
若是是部署在不一樣的服務器,請根據主從分部規則,分開在不一樣的服務器
至此redis集羣即搭建成功! 9:使用redis-cli命令進入集羣環境 redis-cli -c -p 7000
三.測試篇
#redis-trib.rb的check子命令構建 #ip:port能夠是集羣的任意節點 ./redis-trib.rb check 1 127.0.0.1:7000
最後輸出以下信息,沒有任何警告或錯誤,表示集羣啓動成功並處於ok狀態
2):添加新master節點
(1)添加一個master節點:建立一個空節點(empty node),而後將某些slot移動到這個空節點上,這個過程目前須要人工干預
a):根據端口生成配置文件(ps:establish_config.sh是我本身寫的輸出配置腳本)
sh establish_config.sh 6386 > conf/redis-6386.conf
):啓動節點
nohup redis-server /opt/redis/conf/redis-6386.conf > /opt/redis/logs/redis-6386.log 2>&1 &
c):加入空節點到集羣
add-node 將一個節點添加到集羣裏面, 第一個是新節點ip:port, 第二個是任意一個已存在節點ip:port
redis-trib.rb add-node 10.10.34.14:6386 10.10.34.14:6381
node:新節點沒有包含任何數據, 由於它沒有包含任何slot。新加入的加點是一個主節點, 當集羣須要將某個從節點升級爲新的主節點時, 這個新節點不會被選中
d):爲新節點分配slot
redis-trib.rb reshard 10.10.34.14:6386
#根據提示選擇要遷移的slot數量(ps:這裏選擇500) How many slots do you want to move (from 1 to 16384)? 500 #選擇要接受這些slot的node-id
What is the receiving node ID? f51e26b5d5ff74f85341f06f28f125b7254e61bf #選擇slot來源:
#all表示從全部的master從新分配,
#或者數據要提取slot的master節點id,最後用done結束 Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs. Source node #1:all
#打印被移動的slot後,輸入yes開始移動slot以及對應的數據. #Do you want to proceed with the proposed reshard plan (yes/no)? yes #結束
3):添加新的slave節點 a):前三步操做同添加master同樣
b)第四步:redis-cli鏈接上新節點shell,輸入命令:cluster replicate 對應master的node-id
cluster replicate 2b9ebcbd627ff0fd7a7bbcc5332fb09e72788835
note:在線添加slave 時,須要dump整個master進程,並傳遞到slave,再由 slave加載rdb文件到內存,rdb傳輸過程當中Master可能沒法提供服務,整個過程消耗大量io,當心操做.
例如本次添加slave操做產生的rdb文件
-rw-r--r-- 1 root root 34946 Apr 17 18:23 dump-6386.rdb -rw-r--r-- 1 root root 34946 Apr 17 18:23 dump-7386.rdb
4):在線reshard 數據:
對於負載/數據均勻的狀況,能夠在線reshard slot來解決,方法與添加新master的reshard同樣,只是須要reshard的master節點是老節點. 5):刪除一個slave節點
#redis-trib del-node ip:port '<node-id>' redis-trib.rb
del-node
10.10.34.14:7386
'c7ee2fca17cb79fe3c9822ced1d4f6c5e169e378' 6):刪除一個master節點
a):刪除master節點以前首先要使用reshard移除master的所有slot,而後再刪除當前節點(目前只能把被刪除 master的slot遷移到一個節點上)
#把10.10.34.14:6386當前master遷移到10.10.34.14:6380上 redis-trib.rb reshard 10.10.34.14:6380
#根據提示選擇要遷移的slot數量(ps:這裏選擇500)
How many slots do you want to move (from 1 to 16384)? 500(被刪除master的全部slot數量)
#選擇要接受這些slot的node-id(10.10.34.14:6380)
What is the receiving node ID? c4a31c852f81686f6ed8bcd6d1b13accdc947fd2 (ps:10.10.34.14:6380的node-id) Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots. Type 'done' once you entered all the source nodes IDs.
Source node #1:f51e26b5d5ff74f85341f06f28f125b7254e61bf(被刪除master的node-id)
Source node #2:done
#打印被移動的slot後,輸入yes開始移動slot以及對應的數據. #Do you want to proceed with the proposed reshard plan (yes/no)? yes
b):刪除空master節點
redis-trib.rb del-node 10.10.34.14:6386
'f51e26b5d5ff74f85341f06f28f125b7254e61bf' 四:redis cluster 客戶端(Jedis) 1:客戶端基本操做使用
<span style="color: #333333; font-family: Arial, sans-serif;"><span style="color: #333333; font-family: Arial, sans-serif;"> private static BinaryJedisCluster jc; static {
//只給集羣裏一個實例就能夠
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>(); jedisClusterNodes.add(new HostAndPort("10.10.34.14", 6380)); jedisClusterNodes.add(new HostAndPort("10.10.34.14", 6381)); jedisClusterNodes.add(new HostAndPort("10.10.34.14", 6382)); jedisClusterNodes.add(new HostAndPort("10.10.34.14", 6383)); jedisClusterNodes.add(new HostAndPort("10.10.34.14", 6384)); jedisClusterNodes.add(new HostAndPort("10.10.34.14", 7380)); jedisClusterNodes.add(new HostAndPort("10.10.34.14", 7381)); jedisClusterNodes.add(new HostAndPort("10.10.34.14", 7382)); jedisClusterNodes.add(new HostAndPort("10.10.34.14", 7383)); jedisClusterNodes.add(new HostAndPort("10.10.34.14", 7384)); jc = new BinaryJedisCluster(jedisClusterNodes); } @Test
public void testBenchRedisSet() throws Exception { final Stopwatch stopwatch = new Stopwatch(); List list = buildBlogVideos(); for (int i = 0; i < 1000; i++) {
String key = "key:" + i; stopwatch.start();
byte[] bytes1 = protostuffSerializer.serialize(list); jc.setex(key, 60 * 60, bytes1); stopwatch.stop(); }
System.out.println("time=" + stopwatch.toString()); }</span></span> 2:jedis客戶端的坑.
1)cluster環境下redis的slave不接受任何讀寫操做,
2)client端不支持keys批量操做,不支持select dbNum操做,只有一個db:select 0 3)JedisCluster 的info()等單機函數沒法調用,返回(No way to dispatch this command to Redis Cluster)錯誤,.
4)JedisCluster 沒有針對byte[]的API,須要本身擴展(附件是我加的基於byte[]的BinaryJedisCluster api)
redis集羣維護節點操做
一,redis cluster命令行
- //集羣(cluster)
- CLUSTER INFO 打印集羣的信息
- CLUSTER NODES 列出集羣當前已知的全部節點(node),以及這些節點的相關信息。
- //節點(node)
- CLUSTER MEET <ip> <port> 將 ip 和 port 所指定的節點添加到集羣當中,讓它成爲集羣的一份子。
- CLUSTER FORGET <node_id> 從集羣中移除 node_id 指定的節點。
- CLUSTER REPLICATE <node_id> 將當前節點設置爲 node_id 指定的節點的從節點。
- CLUSTER SAVECONFIG 將節點的配置文件保存到硬盤裏面。
- //槽(slot)
- CLUSTER ADDSLOTS <slot> [slot ...] 將一個或多個槽(slot)指派(assign)給當前節點。
- CLUSTER DELSLOTS <slot> [slot ...] 移除一個或多個槽對當前節點的指派。
- CLUSTER FLUSHSLOTS 移除指派給當前節點的全部槽,讓當前節點變成一個沒有指派任何槽的節點。
- CLUSTER SETSLOT <slot> NODE <node_id> 將槽 slot 指派給 node_id 指定的節點,若是槽已經指派給另外一個節點,那麼先讓另外一個節點刪除該槽>,而後再進行指派。
- CLUSTER SETSLOT <slot> MIGRATING <node_id> 將本節點的槽 slot 遷移到 node_id 指定的節點中。
- CLUSTER SETSLOT <slot> IMPORTING <node_id> 從 node_id 指定的節點中導入槽 slot 到本節點。
- CLUSTER SETSLOT <slot> STABLE 取消對槽 slot 的導入(import)或者遷移(migrate)。
- //鍵 (key)
- CLUSTER KEYSLOT <key> 計算鍵 key 應該被放置在哪一個槽上。
- CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的鍵值對數量。
- CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 個 slot 槽中的鍵。
二,添加節點
1,新配置二個測試節點
- # cd /etc/redis
- //新增配置
- # cp redis-6379.conf redis-6378.conf && sed -i "s/6379/6378/g" redis-6378.conf
- # cp redis-6382.conf redis-6385.conf && sed -i "s/6382/6385/g" redis-6385.conf
- //啓動
- # redis-server /etc/redis/redis-6385.conf > /var/log/redis/redis-6385.log 2>&1 &
- # redis-server /etc/redis/redis-6378.conf > /var/log/redis/redis-6378.log 2>&1 &
2,添加主節點
- # redis-trib.rb add-node 192.168.10.219:6378 192.168.10.219:6379
註釋:
192.168.10.219:6378是新增的節點
192.168.10.219:6379集羣任一個舊節點
3,添加從節點
- # redis-trib.rb add-node --slave --master-id 03ccad2ba5dd1e062464bc7590400441fafb63f2 192.168.10.220:6385 192.168.10.219:6379
註釋:
--slave,表示添加的是從節點
--master-id 03ccad2ba5dd1e062464bc7590400441fafb63f2,主節點的node id,在這裏是前面新添加的6378的node id
192.168.10.220:6385,新節點
192.168.10.219:6379集羣任一個舊節點
4,從新分配slot
- # redis-trib.rb reshard 192.168.10.219:6378 //下面是主要過程
- How many slots do you want to move (from 1 to 16384)? 1000 //設置slot數1000
- What is the receiving node ID? 03ccad2ba5dd1e062464bc7590400441fafb63f2 //新節點node id
- Please enter all the source node IDs.
- Type 'all' to use all the nodes as source nodes for the hash slots.
- Type 'done' once you entered all the source nodes IDs.
- Source node #1:all //表示所有節點從新洗牌
- Do you want to proceed with the proposed reshard plan (yes/no)? yes //確認從新分
新增長的主節點,是沒有slots的,
M: 03ccad2ba5dd1e062464bc7590400441fafb63f2 192.168.10.219:6378
slots:0-332,5461-5794,10923-11255 (0 slots) master
主節點若是沒有slots的話,存取數據就都不會被選中。
能夠把分配的過程理解成打撲克牌,all表示你們從新洗牌;輸入某個主節點的node id,而後在輸入done的話,就比如從某個節點,抽牌。
5,查看一下,集羣狀況
- [root@slave2 redis]# redis-trib.rb check 192.168.10.219:6379
- Connecting to node 192.168.10.219:6379: OK
- Connecting to node 192.168.10.220:6385: OK
- Connecting to node 192.168.10.219:6378: OK
- Connecting to node 192.168.10.220:6382: OK
- Connecting to node 192.168.10.220:6383: OK
- Connecting to node 192.168.10.219:6380: OK
- Connecting to node 192.168.10.219:6381: OK
- Connecting to node 192.168.10.220:6384: OK
- >>> Performing Cluster Check (using node 192.168.10.219:6379)
- M: 5d8ef5a7fbd72ac586bef04fa6de8a88c0671052 192.168.10.219:6379
- slots:5795-10922 (5128 slots) master
- 1 additional replica(s)
- S: 9c240333476469e8e2c8e80b089c48f389827265 192.168.10.220:6385
- slots: (0 slots) slave
- replicates 03ccad2ba5dd1e062464bc7590400441fafb63f2
- M: 03ccad2ba5dd1e062464bc7590400441fafb63f2 192.168.10.219:6378
- slots:0-332,5461-5794,10923-11255 (1000 slots) master
- 1 additional replica(s)
- M: 19b042c17d2918fade18a4ad2efc75aa81fd2422 192.168.10.220:6382
- slots:333-5460 (5128 slots) master
- 1 additional replica(s)
- M: b2c50113db7bd685e316a16b423c9b8abc3ba0b7 192.168.10.220:6383
- slots:11256-16383 (5128 slots) master
- 1 additional replica(s)
- S: 6475e4c8b5e0c0ea27547ff7695d05e9af0c5ccb 192.168.10.219:6380
- slots: (0 slots) slave
- replicates 19b042c17d2918fade18a4ad2efc75aa81fd2422
- S: 1ee01fe95bcfb688a50825d54248eea1e6133cdc 192.168.10.219:6381
- slots: (0 slots) slave
- replicates b2c50113db7bd685e316a16b423c9b8abc3ba0b7
- S: 9a2a1d75b8eb47e05eee1198f81a9edd88db5aa1 192.168.10.220:6384
- slots: (0 slots) slave
- replicates 5d8ef5a7fbd72ac586bef04fa6de8a88c0671052
- [OK] All nodes agree about slots configuration.
- >>> Check for open slots...
- >>> Check slots coverage...
- [OK] All 16384 slots covered.
三,改變從節點的master
- //查看一下6378的從節點
- # redis-cli -p 6378 cluster nodes | grep slave | grep 03ccad2ba5dd1e062464bc7590400441fafb63f2
- //將6385加入到新的master
- # redis-cli -c -p 6385 -h 192.168.10.220
- 192.168.10.220:6385> cluster replicate 5d8ef5a7fbd72ac586bef04fa6de8a88c0671052 //新master的node id
- OK
- 192.168.10.220:6385> quit
- //查看新master的slave
- # redis-cli -p 6379 cluster nodes | grep slave | grep 5d8ef5a7fbd72ac586bef04fa6de8a88c0671052
四,刪除節點
1,刪除從節點
- # redis-trib.rb del-node 192.168.10.220:6385 '9c240333476469e8e2c8e80b089c48f389827265'
2,刪除主節點
若是主節點有從節點,將從節點轉移到其餘主節點
若是主節點有slot,去掉分配的slot,而後在刪除主節點
- # redis-trib.rb reshard 192.168.10.219:6378 //取消分配的slot,下面是主要過程
- How many slots do you want to move (from 1 to 16384)? 1000 //被刪除master的全部slot數量
- What is the receiving node ID? 5d8ef5a7fbd72ac586bef04fa6de8a88c0671052 //接收6378節點slot的master
- Please enter all the source node IDs.
- Type 'all' to use all the nodes as source nodes for the hash slots.
- Type 'done' once you entered all the source nodes IDs.
- Source node #1:03ccad2ba5dd1e062464bc7590400441fafb63f2 //被刪除master的node-id
- Source node #2:done
- Do you want to proceed with the proposed reshard plan (yes/no)? yes //取消slot後,reshard
新增master節點後,也進行了這一步操做,當時是分配,如今去掉。反着的。
- # redis-trib.rb del-node 192.168.10.219:6378 '03ccad2ba5dd1e062464bc7590400441fafb63f2'
新的master節點被刪除了,這樣就回到了,就是這篇文章開頭,尚未添加節點的狀態