一、Redis集群介绍

       Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。

       Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误。

       Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令。

       Redis 集群的优势:

自动分割数据到不同的节点上;

整个集群的部分节点失败或者不可达的情况下能够继续处理命令。

       Redis集群的数据分片使用哈希槽,集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,比如当前集群有3个节点,那么:

       节点 A 包含 0 到 5500号哈希槽;

       节点 B 包含5501 到 11000 号哈希槽;

       节点 C 包含11001 到 16384号哈希槽.

      这种结构很容易添加或删除节点,由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态。

      为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品。


二、编译安装相关程序

①下载相关程序

# wget http://download.redis.io/releases/redis-3.0.6.tar.gz
# wget http://nchc.dl.sourceforge.net/project/libpng/zlib/1.2.8/zlib-1.2.8.tar.gz
# wget https://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.4.tar.bz2
# wget https://rubygems.global.ssl.fastly.net/rubygems/rubygems-2.5.1.tgz
# wget https://rubygems.global.ssl.fastly.net/gems/redis-3.2.2.gem


②编译zlib

# gunzip zlib-1.2.8.tar.gz
# tar -xvf zlib-1.2.8.tar
# cd zlib-1.2.8
# ./configure
# make
# make install


③编译ruby

# bunzip2 ruby-2.2.4.tar.bz2
# tar -xvf ruby-2.2.4.tar
# cd ruby-2.2.4
# ./configure -prefix=/usr/local/ruby
# make
Generating RDoc documentation
Parsing sources...
100% [967/967]  vsnprintf.c                                        
Generating RI format into /root/ruby-2.2.4/.ext/rdoc...
  Files:        967
  Classes:     1411 ( 581 undocumented)
  Modules:      280 ( 108 undocumented)
  Constants:   2160 ( 594 undocumented)
  Attributes:  1156 ( 255 undocumented)
  Methods:    10488 (2187 undocumented)
  Total:      15495 (3725 undocumented)
   75.96% documented
  Elapsed: 744.0s
# make install
# cp ruby /bin


④编译rubygems

# tar -zxvf rubygems-2.5.1.tgz
# cd rubygems-2.5.1
# ruby setup.rb
# cp bin/gem /bin

注:编译中出现in 'require': cannot load such file -- json/pure (LoadError)的解决方法:

# gem install json_pure
Fetching: json_pure-1.8.3.gem (100%)
Successfully installed json_pure-1.8.3
Parsing documentation for json_pure-1.8.3
Installing ri documentation for json_pure-1.8.3
1 gem installed


⑤安装gem-redis

# gem install -l redis-3.2.2.gem 
Successfully installed redis-3.2.2
Parsing documentation for redis-3.2.2
Installing ri documentation for redis-3.2.2
1 gem installed


⑥编译安装redis3.0

# wget http://download.redis.io/releases/redis-3.0.6.tar.gz
# tar -zxvf redis-3.0.6.tar.gz
# cd redis-3.0.6
# make
# cp src/redis-server /bin      ##Redis服务器的daemon启动程序
# cp src/redis-cli /bin           ##Redis命令行操作工具
# cp src/redis-trib.rb /bin       ##Redis Cluster工具
# cp src/redis-benchmark /bin       ##Redis性能测试工具
# cp src/redis-check-aof /bin       ##修复坏损坏的aof文件
# cp src/redis-check-dump /bin     ##检查导出工具
# cp src/redis-sentinel /bin     ##Redis集群的管理工具


三、配置Redis集群

①配置redis.conf

# cd redis-3.0.6
# cp redis.conf  /etc/redis-7000.conf
# vi /etc/redis-7000.conf
daemonize yes
port 7000
tcp-backlog 511
timeout 0
tcp-keepalive 0
loglevel notice
maxmemory 10gb
logfile /data/redis/7000/redis-7000.log
databases 16
#slave只读
slave-priority 100
#每秒一次aof写
appendfsync everysec
#关闭在aof rewrite的时候对新的写操作进行fsync
no-appendfsync-on-rewrite yes
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
lua-time-limit 5000
#打开redis集群
cluster-enabled yes
cluster-config-file /data/redis/7000/nodes-7000.conf
#节点互连超时的阀值(单位毫秒)
cluster-node-timeout 15000
cluster-migration-barrier 1
cluster-require-full-coverage no
auto-aof-rewrite-percentage 80-100
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
# cp /etc/redis-7000.conf /etc/redis-7001.conf
# cp /etc/redis-7000.conf /etc/redis-7002.conf
# cp /etc/redis-7000.conf /etc/redis-7003.conf
# cp /etc/redis-7000.conf /etc/redis-7004.conf
# cp /etc/redis-7000.conf /etc/redis-7005.conf

注:各实例配置类似,修改相应端口、文件名即可


②新建相应目录

# mkdir -pv /data/redis/{7000,7001,7002,7003,7004,7005}
mkdir: 已创建目录 "/data/redis"
mkdir: 已创建目录 "/data/redis/7000"
mkdir: 已创建目录 "/data/redis/7001"
mkdir: 已创建目录 "/data/redis/7002"
mkdir: 已创建目录 "/data/redis/7003"
mkdir: 已创建目录 "/data/redis/7004"
mkdir: 已创建目录 "/data/redis/7005"


③启动Redis

# redis-server /etc/redis-7000.conf
# redis-server /etc/redis-7001.conf
# redis-server /etc/redis-7002.conf
# redis-server /etc/redis-7003.conf
# redis-server /etc/redis-7004.conf
# redis-server /etc/redis-7005.conf
# ss -tlnp


四、构建Redis集群并测试

a. 构建Redis集群

①使用ruby工具(redis-trib.rb)构建集群

# 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
>>> Creating cluster
>>> 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: 143b8739a5df1428a50e1c6ec23f8659eadde167 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: 0310fb813aedd48c5e6c380d68a19402cd98523a 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: c8cfe49e70545d8299ad759474ccfe12d9f43b03 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
S: bbf442e1732b5e5a9048fe6692b7038b2677d065 127.0.0.1:7003
   replicates 143b8739a5df1428a50e1c6ec23f8659eadde167
S: 28546f490991cbfbc5eb38d29d144c4389aa1093 127.0.0.1:7004
   replicates 0310fb813aedd48c5e6c380d68a19402cd98523a
S: dd90a66c7b737ffeec88f5b97851655a15fec4a0 127.0.0.1:7005
   replicates c8cfe49e70545d8299ad759474ccfe12d9f43b03
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: 143b8739a5df1428a50e1c6ec23f8659eadde167 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: 0310fb813aedd48c5e6c380d68a19402cd98523a 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: c8cfe49e70545d8299ad759474ccfe12d9f43b03 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
M: bbf442e1732b5e5a9048fe6692b7038b2677d065 127.0.0.1:7003
   slots: (0 slots) master
   replicates 143b8739a5df1428a50e1c6ec23f8659eadde167
M: 28546f490991cbfbc5eb38d29d144c4389aa1093 127.0.0.1:7004
   slots: (0 slots) master
   replicates 0310fb813aedd48c5e6c380d68a19402cd98523a
M: dd90a66c7b737ffeec88f5b97851655a15fec4a0 127.0.0.1:7005
   slots: (0 slots) master
   replicates c8cfe49e70545d8299ad759474ccfe12d9f43b03
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

注:必须输入yes,不能简写

    redis-trib.rb create -------  构建Redis集群

    --replicas 1 --- 指定为Redis  Cluster的每个Master节点配备一个Slave节点,节点角色由顺序决定,先master后slave

 

②查看集群节点

# redis-cli -p 7000 cluster nodes      
bbf442e1732b5e5a9048fe6692b7038b2677d065 127.0.0.1:7003 slave 143b8739a5df1428a50e1c6ec23f8659eadde167 0 1451811402289 4 connected
28546f490991cbfbc5eb38d29d144c4389aa1093 127.0.0.1:7004 slave 0310fb813aedd48c5e6c380d68a19402cd98523a 0 1451811400270 5 connected
143b8739a5df1428a50e1c6ec23f8659eadde167 127.0.0.1:7000 myself,master - 0 0 1 connected 0-5460
c8cfe49e70545d8299ad759474ccfe12d9f43b03 127.0.0.1:7002 master - 0 1451811401279 3 connected 10923-16383
dd90a66c7b737ffeec88f5b97851655a15fec4a0 127.0.0.1:7005 slave c8cfe49e70545d8299ad759474ccfe12d9f43b03 0 1451811404307 6 connected
0310fb813aedd48c5e6c380d68a19402cd98523a 127.0.0.1:7001 master - 0 1451811403300 2 connected 5461-10922


③检查集群

# redis-trib.rb check 127.0.0.1:7000      
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: 143b8739a5df1428a50e1c6ec23f8659eadde167 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: bbf442e1732b5e5a9048fe6692b7038b2677d065 127.0.0.1:7003
   slots: (0 slots) slave
   replicates 143b8739a5df1428a50e1c6ec23f8659eadde167
S: 28546f490991cbfbc5eb38d29d144c4389aa1093 127.0.0.1:7004
   slots: (0 slots) slave
   replicates 0310fb813aedd48c5e6c380d68a19402cd98523a
M: c8cfe49e70545d8299ad759474ccfe12d9f43b03 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: dd90a66c7b737ffeec88f5b97851655a15fec4a0 127.0.0.1:7005
   slots: (0 slots) slave
   replicates c8cfe49e70545d8299ad759474ccfe12d9f43b03
M: 0310fb813aedd48c5e6c380d68a19402cd98523a 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.



④查看集群主节点

# redis-cli -p 7000 cluster nodes | grep master
143b8739a5df1428a50e1c6ec23f8659eadde167 127.0.0.1:7000 myself,master - 0 0 1 connected 0-5460
c8cfe49e70545d8299ad759474ccfe12d9f43b03 127.0.0.1:7002 master - 0 1451814862831 3 connected 10923-16383
0310fb813aedd48c5e6c380d68a19402cd98523a 127.0.0.1:7001 master - 0 1451814860815 2 connected 5461-10922


b.测试Redis集群

①使用redis-cli命令进行测试

# redis-cli -c -p 7000
127.0.0.1:7000> set foo bar
-> Redirected to slot [12182] located at 127.0.0.1:7002
OK
127.0.0.1:7002> set hello world
-> Redirected to slot [866] located at 127.0.0.1:7000
OK
127.0.0.1:7000> get foo
-> Redirected to slot [12182] located at 127.0.0.1:7002
"bar"
127.0.0.1:7002> get hello
-> Redirected to slot [866] located at 127.0.0.1:7000
"world"


②下线Redis节点

向端口号为7002的主节点发送 DEBUG SEGFAULT 命令, 让该主节点崩溃

# redis-cli -p 7002 debug segfault
Error: Server closed the connection
# redis-cli -p 7000 cluster nodes | grep master


③添加Master新节点

# cp /etc/redis-7000.conf /etc/redis-7006.conf(注意更改端口)
# mkdir /data/redis/7006/
# redis-server /etc/redis-7006.conf
# redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000
>>> Adding node 127.0.0.1:7006 to cluster 127.0.0.1:7000
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: 143b8739a5df1428a50e1c6ec23f8659eadde167 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: bbf442e1732b5e5a9048fe6692b7038b2677d065 127.0.0.1:7003
   slots: (0 slots) slave
   replicates 143b8739a5df1428a50e1c6ec23f8659eadde167
S: 28546f490991cbfbc5eb38d29d144c4389aa1093 127.0.0.1:7004
   slots: (0 slots) slave
   replicates 0310fb813aedd48c5e6c380d68a19402cd98523a
M: dd90a66c7b737ffeec88f5b97851655a15fec4a0 127.0.0.1:7005
   slots:10923-16383 (5461 slots) master
   0 additional replica(s)
M: 0310fb813aedd48c5e6c380d68a19402cd98523a 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 127.0.0.1:7006 to make it join the cluster.
[OK] New node added correctly.


④集群重新分片

# redis-trib.rb reshard 127.0.0.1:7006
>>> Performing Cluster Check (using node 127.0.0.1:7006)
M: 8785c3133caac92b022a4852d15d63409497287f 127.0.0.1:7006
   slots:0-165,5461-5627,10923-11088 (499 slots) master
   1 additional replica(s)
S: bbf442e1732b5e5a9048fe6692b7038b2677d065 127.0.0.1:7003
   slots: (0 slots) slave
   replicates 143b8739a5df1428a50e1c6ec23f8659eadde167
S: c8cfe49e70545d8299ad759474ccfe12d9f43b03 127.0.0.1:7002
   slots: (0 slots) slave
   replicates 8785c3133caac92b022a4852d15d63409497287f
M: dd90a66c7b737ffeec88f5b97851655a15fec4a0 127.0.0.1:7005
   slots:11089-16383 (5295 slots) master
   0 additional replica(s)
S: 28546f490991cbfbc5eb38d29d144c4389aa1093 127.0.0.1:7004
   slots: (0 slots) slave
   replicates 0310fb813aedd48c5e6c380d68a19402cd98523a
M: 143b8739a5df1428a50e1c6ec23f8659eadde167 127.0.0.1:7000
   slots:166-5460 (5295 slots) master
   1 additional replica(s)
M: 0310fb813aedd48c5e6c380d68a19402cd98523a 127.0.0.1:7001
   slots:5628-10922 (5295 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 500
##选择要迁移的slot数量
What is the receiving node ID? 8785c3133caac92b022a4852d15d63409497287f
##选择要接受这些slot的node-id?
Source node #1:all
##选择slot来源,all表示从所有master重新分配,也可选择数据要提取slot的master节点id,最后用done结束
......
Do you want to proceed with the proposed reshard plan (yes/no)? yes
##打印被移动的slot后,输入yes开始移动slot以及对应的数据

注:上面7006已分片过一次,由于没有复制,所以重新再分片了一次


⑤删除一个Master节点

<1>. 使用reshard移除master的全部slot

# redis-trib.rb reshard 127.0.0.1:7006
>>> Performing Cluster Check (using node 127.0.0.1:7006)
M: 8785c3133caac92b022a4852d15d63409497287f 127.0.0.1:7006
   slots:0-165,5461-5627,10923-11088 (499 slots) master
   1 additional replica(s)
S: bbf442e1732b5e5a9048fe6692b7038b2677d065 127.0.0.1:7003
   slots: (0 slots) slave
   replicates 143b8739a5df1428a50e1c6ec23f8659eadde167
S: c8cfe49e70545d8299ad759474ccfe12d9f43b03 127.0.0.1:7002
   slots: (0 slots) slave
   replicates 8785c3133caac92b022a4852d15d63409497287f
M: dd90a66c7b737ffeec88f5b97851655a15fec4a0 127.0.0.1:7005
   slots:11089-16383 (5295 slots) master
   0 additional replica(s)
S: 28546f490991cbfbc5eb38d29d144c4389aa1093 127.0.0.1:7004
   slots: (0 slots) slave
   replicates 0310fb813aedd48c5e6c380d68a19402cd98523a
M: 143b8739a5df1428a50e1c6ec23f8659eadde167 127.0.0.1:7000
   slots:166-5460 (5295 slots) master
   1 additional replica(s)
M: 0310fb813aedd48c5e6c380d68a19402cd98523a 127.0.0.1:7001
   slots:5628-10922 (5295 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 500
##根据提示选择要迁移的slot数量
What is the receiving node ID? dd90a66c7b737ffeec88f5b97851655a15fec4a0
##选择要接受这些slot的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:8785c3133caac92b022a4852d15d63409497287f
##被删除master的node-id
Source node #2:done
.....
Do you want to proceed with the proposed reshard plan (yes/no)? yes
##打印被移动的slot后,输入yes开始移动slot以及对应的数据


<2>. 删除空Master节点(删除Slave节点只需该命令)

# redis-trib.rb del-node 127.0.0.1:7006 8785c3133caac92b022a4852d15d63409497287f
>>> Removing node 8785c3133caac92b022a4852d15d63409497287f from cluster 127.0.0.1:7006
>>> Sending CLUSTER FORGET messages to the cluster...
>>> 127.0.0.1:7002 as replica of 127.0.0.1:7005
>>> SHUTDOWN the node.


⑥添加一个从节点

<1>.使用redis-trib.rb命令添加:

# redis-trib.rb add-node --slave 127.0.0.1:7006 127.0.0.1:7000

注:此处的命令和添加一个主节点命令类似,此处并没有指定添加的这个从节点的主节点,这种情况下系统会在其他的复制集中的主节点中随机选取一个作为这个从节点的主节点。


<2>.可通过如下命令指定主节点:

# redis-trib.rb add-node --slave --master-id 143b8739a5df1428a50e1c6ec23f8659eadde167 127.0.0.1:7006 127.0.0.1:7000


<3>.可使用Cluster Replicate 命令添加.该命令也可改变一个从节点的主节点:

redis 127.0.0.1:7006> cluster replicate dd90a66c7b737ffeec88f5b97851655a15fec4a0   ##给主节点7005添加一个从节点


五、Redis Cluster常用管理命令

①集群(cluster)

cluster info     ##打印集群的信息  

cluster nodes  ##列出集群当前已知的所有节点(node),以及其相关信息     


②节点 (node)

cluster meet   ##将IP和PORT所指定的节点添加到集群当中,让其成为集群一员

cluster forget       ##从集群中移除node_id指定的节点

cluster replicate   ##将当前节点设置为node_id指定的节点的从节点

cluster saveconfig   ##将节点的配置文件保存到硬盘里面


③槽(slot)  

cluster addslots [slot ...] ##将一个或多个槽(slot)指派(assign)给当前节点

cluster delslots [slot ...]   ##移除一个或多个槽对当前节点的指派

cluster flushslots ##移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点

cluster setslot node   ##将槽slot指派给node_id指定的节点如果槽已经指派给另一个节点,那么先让另一个节点删除该槽,然后再进行指派

cluster setslot migrating  ##将本节点的槽slot迁移到node_id指定的节点中

cluster setslot importing  ##从node_id指定的节点中导入槽slot到本节点

cluster setslot stable   ##取消对槽slot的导入(import)或者迁移(migrate)


④键 (key)

cluster keyslot        ##计算键key应该被放置在哪个槽上   

cluster countkeysinslot   ##返回槽slot 目前包含的键值对数量 

cluster getkeysinslot     ##返回count个slot 槽中的键