rediscluster

scala操作RedisCluster package calc.bi.udfutils import redis.clients.jedis.JedisCluster import redis.clients.jedis.HostAndPort import redis.clients.jedis.ScanParams import scala.collection.mutable.ListBuffer import scala.co... 阅读详情

redis 是我们目前大规模使用的缓存中间件,由于它强大高效而又便捷的功能,得到了广泛的使用。现在的2.x的稳定版本是2.8.19,也是我们项目中普遍用到的版本。

redis在年初发布了3.0.0,官方支持了redis cluster,也就是集群。至此结束了redis 没有官方集群的时代,之前我们用redis cluster用的最多的应该是twitter 发布的Twemproxy(https://github.com/twitter/twemproxy)

还有就是豌豆荚开发的codis (https://github.com/wandoulabs/codis)

这2个我会在后续去使用它们。下面的文字,我尽量用通熟易懂的方式来阐述。

 

redis cluster 理论知识

截止写这篇文章前,redis 3.x的最新版本是3.0.5。今天的学习和实践就是用这个版本。

 

Redis Cluster设计要点

redis cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。

那么redis 是如何合理分配这些节点和数据的呢?

Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽 (hash slot)的方式来分配的。redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。

注意的是:必须要3个以后的主节点,否则在创建集群时会失败,我们在后续会实践到。

所以,我们假设现在有3个节点已经组成了集群,分别是:A, B, C 三个节点,它们可以是一台机器上的三个端口,也可以是三台不同的服务器。那么,采用哈希槽 (hash slot)的方式来分配16384个slot 的话,它们三个节点分别承担的slot 区间是:

  • 节点A覆盖0-5460;
  • 节点B覆盖5461-10922;
  • 节点C覆盖10923-16383.

如下图所示:

这里写图片描述

那么,现在我想设置一个key ,比如叫my_name:

set my_name yangyi

按照redis cluster的哈希槽算法:CRC16('my_name')%16384 = 2412。 那么就会把这个key 的存储分配到 A 上了。

同样,当我连接(A,B,C)任何一个节点想获取my_name这个key时,也会这样的算法,然后内部跳转到B节点上获取数据。

这种哈希槽的分配方式有好也有坏,好处就是很清晰,比如我想新增一个节点D,redis cluster的这种做法是从各个节点的前面各拿取一部分slot到D上,我会在接下来的实践中实验。大致就会变成这样:

  • 节点A覆盖1365-5460
  • 节点B覆盖6827-10922
  • 节点C覆盖12288-16383
  • 节点D覆盖0-1364,5461-6826,10923-12287

同样删除一个节点也是类似,移动完成后就可以删除这个节点了。

所以redis cluster 就是这样的一个形状:

这里写图片描述

 

Redis Cluster主从模式

redis cluster 为了保证数据的高可用性,加入了主从模式,一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是从主节点拉取数据备份,当这个主节点挂掉后,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉。

上面那个例子里, 集群有ABC三个主节点, 如果这3个节点都没有加入从节点,如果B挂掉了,我们就无法访问整个集群了。A和C的slot也无法访问。

所以我们在集群建立的时候,一定要为每个主节点都添加了从节点, 比如像这样, 集群包含主节点A、B、C, 以及从节点A1、B1、C1, 那么即使B挂掉系统也可以继续正确工作。

B1节点替代了B节点,所以Redis集群将会选择B1节点作为新的主节点,集群将会继续正确地提供服务。 当B重新开启后,它就会变成B1的从节点。

不过需要注意,如果节点B和B1同时挂了,Redis集群就无法继续正确地提供服务了。

流程下图所示:

这里写图片描述

 

redis cluster 动手实践

网上有很多教程,我最先是按照这个教程(http://blog.51yip.com/nosql/1725.html) 一步步的按照这个教程来,可是在最后启动集群的时候第一台机器的6379端口死活启动不了,这样就没有3台主服务器,就完成不了集群。最后也没找到解决办法。[知道原因了:我把redis-trib.rb create --replicas 1的 这个1没有写!!!!]

现在,还是按照官方的教程,全程再演示一次,官方教程是在一台机器上启动6个节点,3个当主,3个当从(http://redis.io/topics/cluster-tutorial):

先下载官方的redis 版本(3.0.5) : http://download.redis.io/releases/redis-3.0.5.tar.gz

下载不了,请自行FQ。我这次是在centos6.5上演示,用的是root 账户。

如果之前已经下载了redis的 2.x版本,只需要将 /usr/local/bin/redis-* 这几个命令先删除即可。

 

1.解压

[root@web3 ~]# tar zxvf redis-3.0.5.tar.gz

2.安装

[root@web3 ~]# cd redis-3.0.5
[root@web3 ~]# make && make install 

3.将redis-trib.rb 复制到/usr/local/bin

[root@web3 redis-3.0.5]# cd src/
[root@web3 src]# cp redis-trib.rb /usr/local/bin

4.开始集群搭建

复制代码

复制代码

[root@web3 redis-3.0.5]# vi redis.conf
#修改以下地方
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

复制代码

复制代码

 

 

新建6个节点:

 

复制代码

复制代码

[root@web3 redis-3.0.5]# mkdir -p /usr/local/cluster-test
[root@web3 redis-3.0.5]# cd /usr/local/cluster-test/
[root@web3 cluster-test]# mkdir 7000
[root@web3 cluster-test]# mkdir 7001
[root@web3 cluster-test]# mkdir 7002
[root@web3 cluster-test]# mkdir 7003
[root@web3 cluster-test]# mkdir 7004
[root@web3 cluster-test]# mkdir 7005

复制代码

复制代码

将redis.conf 分别拷贝到这6个文件夹中,并修改成对应的端口号

 

复制代码

复制代码

#拷贝配置文件
[root@web3 cluster-test]# cp /root/redis-3.0.5/redis.conf /usr/local/cluster-test/7000
[root@web3 cluster-test]# cp /root/redis-3.0.5/redis.conf /usr/local/cluster-test/7001
[root@web3 cluster-test]# cp /root/redis-3.0.5/redis.conf /usr/local/cluster-test/7002
[root@web3 cluster-test]# cp /root/redis-3.0.5/redis.conf /usr/local/cluster-test/7003
[root@web3 cluster-test]# cp /root/redis-3.0.5/redis.conf /usr/local/cluster-test/7004
[root@web3 cluster-test]# cp /root/redis-3.0.5/redis.conf /usr/local/cluster-test/7005
#修改端口号
root@web3 cluster-test]# sed -i "s/7000/7001/g" /usr/local/cluster-test/7001/redis.conf
[root@web3 cluster-test]# sed -i "s/7000/7002/g" /usr/local/cluster-test/7002/redis.conf
[root@web3 cluster-test]# sed -i "s/7000/7003/g" /usr/local/cluster-test/7003/redis.conf
[root@web3 cluster-test]# sed -i "s/7000/7004/g" /usr/local/cluster-test/7004/redis.conf
[root@web3 cluster-test]# sed -i "s/7000/7005/g" /usr/local/cluster-test/7005/redis.conf

复制代码

复制代码

分别,启动这6个节点

复制代码

复制代码

[root@web3 cluster-test]# cd /usr/local/cluster-test/7000/
[root@web3 7000]# redis-server redis.conf
[root@web3 7000]# cd ../7001
[root@web3 7001]# redis-server redis.conf
[root@web3 7001]# cd ../7002
[root@web3 7002]# redis-server redis.conf
[root@web3 7002]# cd ../7003
[root@web3 7003]# redis-server redis.conf
[root@web3 7003]# cd ../7004
[root@web3 7004]# redis-server redis.conf
[root@web3 7004]# cd ../7005
[root@web3 7005]# redis-server redis.conf
[root@web3 7005]#

复制代码

复制代码

查看6个节点的启动进程情况:

 

复制代码

复制代码

[root@web3 7005]# ps -ef|grep redis
root 11380 1 0 07:37 ? 00:00:00 redis-server *:7000 [cluster]
root 11384 1 0 07:37 ? 00:00:00 redis-server *:7001 [cluster]
root 11388 1 0 07:37 ? 00:00:00 redis-server *:7002 [cluster]
root 11392 1 0 07:37 ? 00:00:00 redis-server *:7003 [cluster]
root 11396 1 0 07:37 ? 00:00:00 redis-server *:7004 [cluster]
root 11400 1 0 07:37 ? 00:00:00 redis-server *:7005 [cluster]
root 11404 8259 0 07:38 pts/0 00:00:00 grep redis

复制代码

复制代码

将6个节点连在一起构招成集群

需要用到的命令就是redis-trib.rb,这是官方的一个用ruby写的一个操作redis cluster的命令,所以,你的机器上需要安装ruby。我们先试一下这个命令:

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

因为我们要新建集群, 所以这里使用create命令. --replicas 1 参数表示为每个主节点创建一个从节点. 其他参数是实例的地址集合。

由于我机子上没安装ruby,所以,会报错:

/usr/bin/env: ruby: No such file or directory

那先安装ruby和rubygems: 

[root@web3 7005]# yum install ruby ruby-devel rubygems rpm-build

然后,再执行一次,发现还是报错:

复制代码

[root@web3 7005]# 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
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `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 /usr/local/bin/redis-trib.rb:25
[root@web3 7005]#

复制代码

 原来是ruby和redis的连接没安装好:

 

[root@web3 7005]# gem install redis
Successfully installed redis-3.2.1
1 gem installed
Installing ri documentation for redis-3.2.1...
Installing RDoc documentation for redis-3.2.1...

好了。最重要的时刻来临了,胜败成举在此了,啊啊啊啊啊啊,好激动:

 

复制代码

复制代码

[root@web3 7005]# 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
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: 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000
slots:0-5460 (5461 slots) master
M: cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001
slots:5461-10922 (5462 slots) master
M: dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002
slots:10923-16383 (5461 slots) master
S: d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003
replicates 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4
S: 4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
S: 30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005
replicates dfa0754c7854a874a6ebd2613b86140ad97701fc
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: 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000
slots:0-5460 (5461 slots) master
M: cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001
slots:5461-10922 (5462 slots) master
M: dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002
slots:10923-16383 (5461 slots) master
M: d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003
slots: (0 slots) master
replicates 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4
M: 4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004
slots: (0 slots) master
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
M: 30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005
slots: (0 slots) master
replicates dfa0754c7854a874a6ebd2613b86140ad97701fc
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

复制代码

复制代码

 

哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈。终于他妈的成功了!!!!

Redis-trib会提示你做了什么配置, 输入yes接受. 集群就被配置和加入了, 意思是, 实例会经过互相交流后启动。

测试集群的状态:

 

复制代码

复制代码

[root@web3 7000]# redis-trib.rb check 127.0.0.1:7000
Connecting to node 127.0.0.1:7000: 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:7005: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7004: OK
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000
slots:0-5460 (5461 slots) master
1 additional replica(s)
M: dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003
slots: (0 slots) slave
replicates 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4
S: 30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005
slots: (0 slots) slave
replicates dfa0754c7854a874a6ebd2613b86140ad97701fc
M: cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001
slots:5461-10922 (5462 slots) master
1 additional replica(s)
S: 4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004
slots: (0 slots) slave
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

复制代码

复制代码

 

可以看到有3个主节点,3个从节点。每个节点都是成功的连接状态。

3个主节点[M]是:

7000 (3707debcbe7be66d4a1968eaf3a5ffaf4308efa4) 
7001 (cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c) 
7002 (dfa0754c7854a874a6ebd2613b86140ad97701fc)

3个从节点[S]是:

7003 (d2237fdcfbba672de766b913d1186cebcb6e1761)->7000 
7004 (4b4aef8b48c427a3c903518339d53b6447c58b93)->7001 
7005 (30858dbf483b61b9838d5c1f853a60beaa4e7afd) ->7002

 

5. 测试连接集群

刚才集群搭建成功了。按照redis cluster的特点,它是去中心化,每个节点都是对等的,所以,你连接哪个节点都可以获取和设置数据,我们来试一下。

redis-cli是redis默认的客户端工具,启动时加上`-c`参数,就可以连接到集群。

连接任意一个节点端口:

 

[root@web3 7000]# redis-cli -c -p 7000
127.0.0.1:7000>

设置一个值:

 

127.0.0.1:7000> set my_name yangyi
-> Redirected to slot [12803] located at 127.0.0.1:7002
OK
127.0.0.1:7002> get my_name
"yangyi"
127.0.0.1:7002>

前面理论知识我们知道了,分配key的时候,它会使用CRC16('my_name')%16384算法,来计算,将这个key 放到哪个节点,这里分配到了12803slot 就分配到了7002(10923-16383)这个节点上。

Redirected to slot [12803] located at 127.0.0.1:7002

redis cluster 采用的方式很直接,它直接跳转到7002 节点了,而不是还在自身的7000节点。

好,现在我们连接7005这个从节点:

 

[root@web3 7000]# redis-cli -c -p 7005
127.0.0.1:7005> get my_name
-> Redirected to slot [12803] located at 127.0.0.1:7002
"yangyi"
127.0.0.1:7002>

我们同样是获取my_name的值,它同样也是跳转到了7002上。

我们再尝试一些其他的可以:

 

复制代码

复制代码

127.0.0.1:7002> set age 123
-> Redirected to slot [741] located at 127.0.0.1:7000
OK
127.0.0.1:7000> set height 565
-> Redirected to slot [8223] located at 127.0.0.1:7001
OK
127.0.0.1:7001> set sex 1
-> Redirected to slot [2584] located at 127.0.0.1:7000
OK
127.0.0.1:7000> set home china
-> Redirected to slot [10814] located at 127.0.0.1:7001
OK
127.0.0.1:7001> set city shanghai
-> Redirected to slot [11479] located at 127.0.0.1:7002
OK
127.0.0.1:7002> set citylocate shanghaipudong
OK
127.0.0.1:7001> set wsdwxzx hhh
-> Redirected to slot [15487] located at 127.0.0.1:7002
OK
127.0.0.1:7002> zadd erew 333 rrr
-> Redirected to slot [10576] located at 127.0.0.1:7001
(integer) 1
127.0.0.1:7000> zrange erew 0 -1
-> Redirected to slot [10576] located at 127.0.0.1:7001
1) "rrr"
127.0.0.1:7001>

复制代码

复制代码

可以看出,数据都会在7000-7002 这3个主节点来跳转存粗。

6. 测试集群中的节点挂掉

上面我们建立来了一个集群。3个主节点[7000-7002]提供数据存粗和读取,3个从节点[7003-7005]则是负责把[7000-7002]的数据同步到自己的节点上来,我们来看一下[7003-7005]的appendonly.aof的内容。看看是不是不这样:

 

复制代码

复制代码

[root@web3 7005]# cd /usr/local/cluster-test/7003
[root@web3 7003]# vi appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$3
age
$3
123
*3
$3
set
$3
sex
$1
1
*3
$3
set
$3
job
$3
php

复制代码

复制代码

我们看下,的确是从7000节点上同步过来的数据,7004,7005也是。

下面,我们先来模拟其中一台Master主服务器挂掉的情况,那就7000挂掉吧:

 

复制代码

复制代码

[root@web3 7003]# ps -ef|grep redis
root 11380 1 0 07:37 ? 00:00:03 redis-server *:7000 [cluster]
root 11384 1 0 07:37 ? 00:00:03 redis-server *:7001 [cluster]
root 11388 1 0 07:37 ? 00:00:03 redis-server *:7002 [cluster]
root 11392 1 0 07:37 ? 00:00:03 redis-server *:7003 [cluster]
root 11396 1 0 07:37 ? 00:00:04 redis-server *:7004 [cluster]
root 11400 1 0 07:37 ? 00:00:03 redis-server *:7005 [cluster]
[root@web3 7003]# kill 11380
[root@web3 7003]#

复制代码

复制代码

好,安装前面的理论,7000主节点挂掉了,那么这个时候,7000的从节点只有7003一个,肯定7003就会被选举称Master节点了:

 

复制代码

复制代码

[root@web3 7003]# redis-trib.rb check 127.0.0.1:7000
Connecting to node 127.0.0.1:7000: [ERR] Sorry, can't connect to node 127.0.0.1:7000
[root@web3 7003]# redis-trib.rb check 127.0.0.1:7001
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7002: OK
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001
slots:5461-10922 (5462 slots) master
1 additional replica(s)
S: 4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004
slots: (0 slots) slave
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
S: 30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005
slots: (0 slots) slave
replicates dfa0754c7854a874a6ebd2613b86140ad97701fc
M: d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003
slots:0-5460 (5461 slots) master
0 additional replica(s)
M: dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002
slots:10923-16383 (5461 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.
[root@web3 7003]#

复制代码

复制代码

看了下,上面有了三个M 节点了,果真,7003被选取成了替代7000成为主节点了。那我们来获取原先存在7000节点的数据:

 

[root@web3 7003]# redis-cli -c -p 7001
127.0.0.1:7001> get sex
-> Redirected to slot [2584] located at 127.0.0.1:7003
"1"
127.0.0.1:7003>

数据果真没有丢失,而是从7003上面获取了。

OK。我们再来模拟 7000节点重新启动了的情况,那么它还会自动加入到集群中吗?那么,7000这个节点上充当什么角色呢? 我们试一下:

重新启动 7000 节点:

     

复制代码

复制代码

[root@web3 7003]# cd ../7000
[root@web3 7000]# ll
total 56
-rw-r--r-- 1 root root 114 Oct 17 08:16 appendonly.aof
-rw-r--r-- 1 root root 43 Oct 17 08:37 dump.rdb
-rw-r--r-- 1 root root 745 Oct 17 08:00 nodes.conf
-rw-r--r-- 1 root root 41550 Oct 17 07:37 redis.conf
[root@web3 7000]# redis-server redis.conf

复制代码

复制代码

 

     启动好了,现在,再来检查一下集群:

 

复制代码

复制代码

redis-trib.rb check 127.0.0.1:700`
 
[root@web3 7000]# redis-trib.rb check 127.0.0.1:7001
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7002: OK
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001
slots:5461-10922 (5462 slots) master
1 additional replica(s)
S: 4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004
slots: (0 slots) slave
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
S: 30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005
slots: (0 slots) slave
replicates dfa0754c7854a874a6ebd2613b86140ad97701fc
M: d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003
slots:0-5460 (5461 slots) master
1 additional replica(s)
S: 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000
slots: (0 slots) slave
replicates d2237fdcfbba672de766b913d1186cebcb6e1761
M: dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002
slots:10923-16383 (5461 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.

复制代码

复制代码

你看,7000节点启动起来了,它却作为了 70003 的从节点了。验证了之前的这张图:

这里写图片描述

一定要保证有3个master 节点,不然,集群就挂掉了。

 

7. 集群中新加入节点

我们再来测试一下,新加入一个节点,分2种情况,1是作为主节点,2是作为一个节点的从节点。我们分别来试一下:

1. 新建一个 7006 节点 作为一个新的主节点加入:

首先就是新建一个 7006的文件夹和redis.conf:

 

[root@web3 cluster-test]# cd /usr/local/cluster-test/
[root@web3 cluster-test]# mkdir 7006
[root@web3 cluster-test]# cp 7005/redis.conf 7006/redis.conf
#修改端口
[root@web3 cluster-test]sed -i "s/7005/7006/g" /usr/local/cluster-test/7006/redis.conf

启动 7006 

复制代码

复制代码

[root@web3 7006]# redis-server redis.conf
[root@web3 7006]# ps -ef|grep redis
root 11384 1 0 07:37 ? 00:00:05 redis-server *:7001 [cluster]
root 11388 1 0 07:37 ? 00:00:05 redis-server *:7002 [cluster]
root 11392 1 0 07:37 ? 00:00:05 redis-server *:7003 [cluster]
root 11396 1 0 07:37 ? 00:00:06 redis-server *:7004 [cluster]
root 11400 1 0 07:37 ? 00:00:05 redis-server *:7005 [cluster]
root 12100 1 0 08:42 ? 00:00:01 redis-server *:7000 [cluster]
root 12132 1 0 09:09 ? 00:00:00 redis-server *:7006 [cluster]
root 12136 8259 0 09:10 pts/0 00:00:00 grep redis

复制代码

复制代码

ok,7006 端口已经启动好了,并且进程也存在了,下面就是加入到集群中,也是得用到redis-trib.rb命令:

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

add-node是加入指令,127.0.0.1:7006 表示新加入的节点,127.0.0.1:7000 表示加入的集群的一个节点,用来辨识是哪个集群,理论上哪个都可以。

 

复制代码

复制代码

[root@web3 7006]# 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
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7002: OK
>>> Performing Cluster Check (using node 127.0.0.1:7000)
S: 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000
slots: (0 slots) slave
replicates d2237fdcfbba672de766b913d1186cebcb6e1761
S: 4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004
slots: (0 slots) slave
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
S: 30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005
slots: (0 slots) slave
replicates dfa0754c7854a874a6ebd2613b86140ad97701fc
M: d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003
slots:0-5460 (5461 slots) master
1 additional replica(s)
M: cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001
slots:5461-10922 (5462 slots) master
1 additional replica(s)
M: dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002
slots:10923-16383 (5461 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.
Connecting to node 127.0.0.1:7006: OK
>>> Send CLUSTER MEET to node 127.0.0.1:7006 to make it join the cluster.
[OK] New node added correctly.

复制代码

复制代码

    

这个命令执行完成之后,它顺便检查来其他的6个节点都是成功的,最后几句话:

 

Connecting to node 127.0.0.1:7006: OK
>>> Send CLUSTER MEET to node 127.0.0.1:7006 to make it join the cluster.
[OK] New node added correctly.

表示新的节点连接成功了,而且也已经加入到集群了,我们再来检查一下:

复制代码

复制代码

[root@web3 7006]# redis-trib.rb check 127.0.0.1:7006
Connecting to node 127.0.0.1:7006: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7003: OK
>>> Performing Cluster Check (using node 127.0.0.1:7006)
M: efc3131fbdc6cf929720e0e0f7136cae85657481 127.0.0.1:7006
slots: (0 slots) master
0 additional replica(s)
M: cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001
slots:5461-10922 (5462 slots) master
1 additional replica(s)
S: 4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004
slots: (0 slots) slave
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
S: 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000
slots: (0 slots) slave
replicates d2237fdcfbba672de766b913d1186cebcb6e1761
M: dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: 30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005
slots: (0 slots) slave
replicates dfa0754c7854a874a6ebd2613b86140ad97701fc
M: d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003
slots:0-5460 (5461 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.

复制代码

复制代码

 

 

可以看到了,7006 已经成为了主节点。

我们也可以连接到客户端后,来看这个集群节点情况:

 

复制代码

复制代码

[root@web3 7006]# redis-cli -c -p 7006
127.0.0.1:7006> cluster nodes
cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001 master - 0 1445073797986 2 connected 5461-10922
4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004 slave cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 0 1445073799497 2 connected
efc3131fbdc6cf929720e0e0f7136cae85657481 127.0.0.1:7006 myself,master - 0 0 0 connected
3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000 slave d2237fdcfbba672de766b913d1186cebcb6e1761 0 1445073797482 7 connected
dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002 master - 0 1445073798489 3 connected 10923-16383
30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005 slave dfa0754c7854a874a6ebd2613b86140ad97701fc 0 1445073798993 3 connected
d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003 master - 0 1445073799498 7 connected 0-5460
127.0.0.1:7006>

复制代码

复制代码

可以看到 有7个节点。7006 也作为了master节点,但是,但是,你看看后面的:

 

efc3131fbdc6cf929720e0e0f7136cae85657481 127.0.0.1:7006
slots: (0 slots) master

卧槽,什么情况。o slots 也就是说,虽然它现在是主节点,但是,缺没有分配任何节点给它,也就是它现在还不负责数据存取。那加上去有毛用啊!!!!

看来,redis cluster 不是在新加节点的时候帮我们做好了迁移工作,需要我们手动对集群进行重新分片迁移,也是这个命令:

redis-trib.rb reshard 127.0.0.1:7000

这个命令是用来迁移slot节点的,后面的127.0.0.1:7000是表示是哪个集群,端口填[7000-7006]都可以,我们运行下:

 

  1. 复制代码

    复制代码

    [root@web3 7006]# redis-trib.rb reshard 127.0.0.1:7000
    Connecting to node 127.0.0.1:7006: OK
    Connecting to node 127.0.0.1:7001: OK
    Connecting to node 127.0.0.1:7004: OK
    Connecting to node 127.0.0.1:7000: OK
    Connecting to node 127.0.0.1:7002: OK
    Connecting to node 127.0.0.1:7005: OK
    Connecting to node 127.0.0.1:7003: OK
    >>> Performing Cluster Check (using node 127.0.0.1:7006)
    M: efc3131fbdc6cf929720e0e0f7136cae85657481 127.0.0.1:7006
    slots: (0 slots) master
    0 additional replica(s)
    M: cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001
    slots:5461-10922 (5462 slots) master
    1 additional replica(s)
    S: 4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004
    slots: (0 slots) slave
    replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
    S: 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000
    slots: (0 slots) slave
    replicates d2237fdcfbba672de766b913d1186cebcb6e1761
    M: dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002
    slots:10923-16383 (5461 slots) master
    1 additional replica(s)
    S: 30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005
    slots: (0 slots) slave
    replicates dfa0754c7854a874a6ebd2613b86140ad97701fc
    M: d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003
    slots:0-5460 (5461 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)?

    复制代码

    复制代码

它提示我们需要迁移多少slot到7006上,我们可以算一下:16384/4 = 4096,也就是说,为了平衡分配起见,我们需要移动4096个槽点到7006上。

好,那输入4096:

 

How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID?

它又提示我们,接受的node ID是多少,7006的id 我们通过上面就可以看到是efc3131fbdc6cf929720e0e0f7136cae85657481 :

 

What is the receiving node ID? efc3131fbdc6cf929720e0e0f7136cae85657481
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:

接着, redis-trib 会向你询问重新分片的源节点(source node), 也即是, 要从哪个节点中取出 4096 个哈希槽, 并将这些槽移动到7006节点上面。

如果我们不打算从特定的节点上取出指定数量的哈希槽, 那么可以向 redis-trib 输入 all , 这样的话, 集群中的所有主节点都会成为源节点, redis-trib 将从各个源节点中各取出一部分哈希槽, 凑够 4096 个, 然后移动到7006节点上:

 

Source node #1:all

接下来就开始迁移了,并且会询问你是否确认:

复制代码

复制代码

Moving slot 1359 from d2237fdcfbba672de766b913d1186cebcb6e1761
Moving slot 1360 from d2237fdcfbba672de766b913d1186cebcb6e1761
Moving slot 1361 from d2237fdcfbba672de766b913d1186cebcb6e1761
Moving slot 1362 from d2237fdcfbba672de766b913d1186cebcb6e1761
Moving slot 1363 from d2237fdcfbba672de766b913d1186cebcb6e1761
Moving slot 1364 from d2237fdcfbba672de766b913d1186cebcb6e1761
Do you want to proceed with the proposed reshard plan (yes/no)?

复制代码

复制代码

输入 yes 并使用按下回车之后, redis-trib 就会正式开始执行重新分片操作, 将指定的哈希槽从源节点一个个地移动到7006节点上面。

迁移完毕之后,我们来检查下:

 

复制代码

复制代码

[root@web3 7006]# redis-trib.rb check 127.0.0.1:7000
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7006: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7002: OK
>>> Performing Cluster Check (using node 127.0.0.1:7000)
S: 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000
slots: (0 slots) slave
replicates d2237fdcfbba672de766b913d1186cebcb6e1761
M: efc3131fbdc6cf929720e0e0f7136cae85657481 127.0.0.1:7006
slots:0-1364,5461-6826,10923-12287 (4096 slots) master
0 additional replica(s)
S: 4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004
slots: (0 slots) slave
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
S: 30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005
slots: (0 slots) slave
replicates dfa0754c7854a874a6ebd2613b86140ad97701fc
M: d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003
slots:1365-5460 (4096 slots) master
1 additional replica(s)
M: cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001
slots:6827-10922 (4096 slots) master
1 additional replica(s)
M: dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002
slots:12288-16383 (4096 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.

复制代码

复制代码

我们着重看7006:

0-1364,5461-6826,10923-12287 (4096 slots)

这些原来在其他节点上的slot 杯迁移到了7006上。原来,它只是间隔的移动,并不是衔接的整体移动,我们看下有数据了没?

 

复制代码

复制代码

[root@web3 7006]# redis-cli -c -p 7006
127.0.0.1:7006> keys *
1) "city"
2) "age"
3) "citylocate"
127.0.0.1:7006> get city
"shanghai"

复制代码

复制代码

非常赞,已经有数据了。

 

2. 新建一个 7007从节点,作为7006的从节点

我们再新建一个节点7007,步骤类似,就先省略了。建好后,启动起来,我们看如何把它加入到集群中的从节点中:

[root@web3 7007]# redis-trib.rb add-node --slave 127.0.0.1:7007 127.0.0.1:7000
add-node的时候加上--slave表示是加入到从节点中,但是这样加,是随机的。这里的命令行完全像我们在添加一个新主服务器时使用的一样,所以我们没有指定要给哪个主服 务器添加副本。这种情况下,redis-trib 会将7007作为一个具有较少副本的随机的主服务器的副本。

那么,你猜,它会作为谁的从节点,应该是7006,因为7006还没有从节点。我们运行下。

 

复制代码

复制代码

[root@web3 7007]# redis-trib.rb add-node --slave 127.0.0.1:7007 127.0.0.1:7000
...
...
[OK] All 16384 slots covered.
Automatically selected master 127.0.0.1:7006
Connecting to node 127.0.0.1:7007: OK
>>> Send CLUSTER MEET to node 127.0.0.1:7007 to make it join the cluster.
Waiting for the cluster to join.
>>> Configure node as replica of 127.0.0.1:7006.
[OK] New node added correctly.

复制代码

复制代码

上面提示说,自动选择了7006作为master节点。并且成功了。我们检查下:

 

复制代码

复制代码

[root@web3 7007]# redis-trib.rb check 127.0.0.1:7000
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7006: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7007: OK
Connecting to node 127.0.0.1:7002: OK
>>> Performing Cluster Check (using node 127.0.0.1:7000)
S: 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000
slots: (0 slots) slave
replicates d2237fdcfbba672de766b913d1186cebcb6e1761
M: efc3131fbdc6cf929720e0e0f7136cae85657481 127.0.0.1:7006
slots:0-1364,5461-6826,10923-12287 (4096 slots) master
1 additional replica(s)
S: 4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004
slots: (0 slots) slave
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
S: 30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005
slots: (0 slots) slave
replicates dfa0754c7854a874a6ebd2613b86140ad97701fc
M: d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003
slots:1365-5460 (4096 slots) master
1 additional replica(s)
M: cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001
slots:6827-10922 (4096 slots) master
1 additional replica(s)
S: 86d05e7c2b197dc182b5e71069e791d033cf899e 127.0.0.1:7007
slots: (0 slots) slave
replicates efc3131fbdc6cf929720e0e0f7136cae85657481
M: dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002
slots:12288-16383 (4096 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.

复制代码

复制代码

果然,7007加入到了7006的从节点当中。

你说,我如果想指定一个主节点行不行?当然可以。我们再建一个7008节点。

 

复制代码

复制代码

redis-trib.rb add-node --slave --master-id efc3131fbdc6cf929720e0e0f7136cae85657481 127.0.0.1:7008 127.0.0.1:7000
--master-id 表示指定的主节点node id。这里指定的是 7006 这个主节点。

 
Waiting for the cluster to join.
>>> Configure node as replica of 127.0.0.1:7006.
[OK] New node added correctly.
[root@web3 7008]#

复制代码

复制代码

提示我们已经作为7006的附属品,也就是加入到7006的从节点来了,照这么说,7006就有2个从节点了,我们看一下:

 

复制代码

redis-cli -c -p 7008 cluster nodes |grep efc3131fbdc6cf929720e0e0f7136cae85657481
86d05e7c2b197dc182b5e71069e791d033cf899e 127.0.0.1:7007 slave efc3131fbdc6cf929720e0e0f7136cae85657481 0 1445089507786 8 connected
efc3131fbdc6cf929720e0e0f7136cae85657481 127.0.0.1:7006 master - 0 1445089508289 8 connected 0-1364 5461-6826 10923-12287
44321e7d619410dc4e0a8745366610a0d06d2395 127.0.0.1:7008 myself,slave efc3131fbdc6cf929720e0e0f7136cae85657481 0 0 0 connected

复制代码

我们过滤了下看结果,果真,7007和7008是7006的从节点了。

刚好,我们再做一个实验,我把7006的杀掉,看7007和7008谁会变成主节点:

 

  1. 复制代码

    复制代码

    [root@web3 7008]# ps -ef|grep redis
    root 11384 1 0 09:56 ? 00:00:16 redis-server *:7001 [cluster]
    root 11388 1 0 09:56 ? 00:00:16 redis-server *:7002 [cluster]
    root 11392 1 0 09:56 ? 00:00:16 redis-server *:7003 [cluster]
    root 11396 1 0 09:56 ? 00:00:15 redis-server *:7004 [cluster]
    root 11400 1 0 09:56 ? 00:00:15 redis-server *:7005 [cluster]
    root 12100 1 0 11:01 ? 00:00:11 redis-server *:7000 [cluster]
    root 12132 1 0 11:28 ? 00:00:11 redis-server *:7006 [cluster]
    root 12202 1 0 13:14 ? 00:00:02 redis-server *:7007 [cluster]
    root 12219 1 0 13:39 ? 00:00:00 redis-server *:7008 [cluster]
    root 12239 8259 0 13:49 pts/0 00:00:00 grep redis
    [root@web3 7008]# kill 12132
    [root@web3 7008]# redis-cli -c -p 7008
    127.0.0.1:7008> get ss5rtr
    -> Redirected to slot [1188] located at 127.0.0.1:7007
    "66"
    127.0.0.1:7007> cluster nodes
    efc3131fbdc6cf929720e0e0f7136cae85657481 127.0.0.1:7006 master,fail - 1445089780668 1445089779963 8 disconnected
    d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003 master - 0 1445089812195 7 connected 1365-5460
    30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005 slave dfa0754c7854a874a6ebd2613b86140ad97701fc 0 1445089813710 3 connected
    86d05e7c2b197dc182b5e71069e791d033cf899e 127.0.0.1:7007 myself,master - 0 0 10 connected 0-1364 5461-6826 10923-12287
    cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001 master - 0 1445089814214 2 connected 6827-10922
    4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004 slave cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 0 1445089812701 2 connected
    44321e7d619410dc4e0a8745366610a0d06d2395 127.0.0.1:7008 slave 86d05e7c2b197dc182b5e71069e791d033cf899e 0 1445089814214 10 connected
    3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000 slave d2237fdcfbba672de766b913d1186cebcb6e1761 0 1445089813204 7 connected
    dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002 master - 0 1445089813204 3 connected 12288-16383
    127.0.0.1:7007>

    复制代码

    复制代码

     

看,7007获得了成为主节点的机会,7008就变成了7007的从节点。

那么这个时候,重启7006节点,那么他就会变成了一个7007的从节点了。

 

复制代码

复制代码

27.0.0.1:7008> cluster nodes
30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005 slave dfa0754c7854a874a6ebd2613b86140ad97701fc 0 1445089986148 3 connected
86d05e7c2b197dc182b5e71069e791d033cf899e 127.0.0.1:7007 master - 0 1445089986652 10 connected 0-1364 5461-6826 10923-12287
d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003 master - 0 1445089986148 7 connected 1365-5460
cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001 master - 0 1445089987155 2 connected 6827-10922
efc3131fbdc6cf929720e0e0f7136cae85657481 127.0.0.1:7006 slave 86d05e7c2b197dc182b5e71069e791d033cf899e 0 1445089985644 10 connected
44321e7d619410dc4e0a8745366610a0d06d2395 127.0.0.1:7008 myself,slave 86d05e7c2b197dc182b5e71069e791d033cf899e 0 0 0 connected
dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002 master - 0 1445089986652 3 connected 12288-16383
4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004 slave cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 0 1445089987660 2 connected
3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000 slave d2237fdcfbba672de766b913d1186cebcb6e1761 0 1445089985644 7 connected
127.0.0.1:7008>

复制代码

复制代码

3. 移除一个主节点

有加肯定有减,redis cluster同样支持移除节点功能,同样也是redis-trib.rb的用法:

redis-trib del-node 127.0.0.1:7000 `<node-id>`

和新加节点有点不同的是,移除需要节点的node-id。那我们尝试将7007这个主节点移除:

 

复制代码

复制代码

[root@web3 7006]# redis-trib.rb del-node 127.0.0.1:7000 86d05e7c2b197dc182b5e71069e791d033cf899e
>>> Removing node 86d05e7c2b197dc182b5e71069e791d033cf899e from cluster 127.0.0.1:7000
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7006: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7007: OK
Connecting to node 127.0.0.1:7008: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7002: OK
[ERR] Node 127.0.0.1:7007 is not empty! Reshard data away and try again.

复制代码

复制代码

报错了,它提示我们说,由于7007里面已经有数据了,不能被移除,要先将它的数据转移出去。也就是说得重新分片,用上面增加新节点后的分片方式一样,用我们再来一遍:

redis-trib.rb reshard 127.0.0.1:7000

由于中间太多内容,就省略不重要的,只简单说明下关键的几步:

 

M: 86d05e7c2b197dc182b5e71069e791d033cf899e 127.0.0.1:7007
slots:0-1364,5461-6826,10923-12287 (4096 slots) master
How many slots do you want to move (from 1 to 16384)?

提示,我们要分多少个槽点,由于7007上有4096个槽点,所以这里填写4096

 

How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID?

提示我们,需要移动到哪个id上,那就填7001的吧:

 

What is the receiving node ID? cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
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:

这里就是关键了,它要我们从哪个节点去转移数据到7001,因为我们是要删除7007的,所以,我们就得7007的id了

 

Source node #1:86d05e7c2b197dc182b5e71069e791d033cf899e
Source node #2:done
Do you want to proceed with the proposed reshard plan (yes/no)? yes

ok,这样就迁移好了。我们看看7007是否为空了:

 

[root@web3 7006]# redis-cli -c -p 7007
127.0.0.1:7007> keys *
(empty list or set)
127.0.0.1:7007> cluster nodes
86d05e7c2b197dc182b5e71069e791d033cf899e 127.0.0.1:7007 myself,master - 0 0 10 connected

果然为空了,好。现在再进行移除节点操作:

 

复制代码

复制代码

[root@web3 7006]# redis-trib.rb del-node 127.0.0.1:7000 86d05e7c2b197dc182b5e71069e791d033cf899e
>>> Removing node 86d05e7c2b197dc182b5e71069e791d033cf899e from cluster 127.0.0.1:7000
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7006: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7007: OK
Connecting to node 127.0.0.1:7008: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7002: OK
>>> Sending CLUSTER FORGET messages to the cluster...
>>> 127.0.0.1:7006 as replica of 127.0.0.1:7001
>>> 127.0.0.1:7008 as replica of 127.0.0.1:7001
>>> SHUTDOWN the node.

复制代码

复制代码

哈哈哈哈哈,删除成功,而且还很人性化的将7006和70082个没了爹的孩子送给了7001。好评👌

我们再检查一下:7007 已经移除,连不上了。

 

复制代码

复制代码

[root@web3 7006]# redis-trib.rb check 127.0.0.1:7007
Connecting to node 127.0.0.1:7007: [ERR] Sorry, can't connect to node 127.0.0.1:7007
 
[root@web3 7006]# redis-trib.rb check 127.0.0.1:7008
Connecting to node 127.0.0.1:7008: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7006: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7000: OK
>>> Performing Cluster Check (using node 127.0.0.1:7008)
S: 44321e7d619410dc4e0a8745366610a0d06d2395 127.0.0.1:7008
slots: (0 slots) slave
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
S: 30858dbf483b61b9838d5c1f853a60beaa4e7afd 127.0.0.1:7005
slots: (0 slots) slave
replicates dfa0754c7854a874a6ebd2613b86140ad97701fc
M: d2237fdcfbba672de766b913d1186cebcb6e1761 127.0.0.1:7003
slots:1365-5460 (4096 slots) master
1 additional replica(s)
M: cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c 127.0.0.1:7001
slots:0-1364,5461-12287 (8192 slots) master
3 additional replica(s)
S: efc3131fbdc6cf929720e0e0f7136cae85657481 127.0.0.1:7006
slots: (0 slots) slave
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
M: dfa0754c7854a874a6ebd2613b86140ad97701fc 127.0.0.1:7002
slots:12288-16383 (4096 slots) master
1 additional replica(s)
S: 4b4aef8b48c427a3c903518339d53b6447c58b93 127.0.0.1:7004
slots: (0 slots) slave
replicates cb5c04b6160c3b7e18cad5d49d8e2987b27e0d6c
S: 3707debcbe7be66d4a1968eaf3a5ffaf4308efa4 127.0.0.1:7000
slots: (0 slots) slave
replicates d2237fdcfbba672de766b913d1186cebcb6e1761
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@web3 7006]#

复制代码

复制代码

7006和7008果然也成功加入到了7001的大家庭。

 

4. 移除一个从节点

移除一个从节点就简单的多了,因为不需要考虑数据的迁移,我们7008给移除:

 

复制代码

复制代码

[root@web3 7006]# redis-trib.rb del-node 127.0.0.1:7005 44321e7d619410dc4e0a8745366610a0d06d2395
>>> Removing node 44321e7d619410dc4e0a8745366610a0d06d2395 from cluster 127.0.0.1:7005
Connecting to node 127.0.0.1:7005: 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:7004: OK
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7006: OK
Connecting to node 127.0.0.1:7008: OK
Connecting to node 127.0.0.1:7003: OK
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
[root@web3 7006]# redis-trib.rb check 127.0.0.1:7008
Connecting to node 127.0.0.1:7008: [ERR] Sorry, can't connect to node 127.0.0.1:7008

复制代码

复制代码

 

移除成功。

 

redis单例、主从模式、sentinel以及集群的配置方式及优缺点对比 

原

 

荐

张旭峰

  张旭峰 发布于 2017/05/21 01:32 

字数 5452

 

阅读 3540

 

收藏 140

 

点赞 7

 

 评论 9

redissentinelcluster高可用主从模式

 

      redis作为一种高效的缓存框架,使用是非常广泛的,在数据存储上,在运行时其将数据存储在内存中,以实现数据的高效读写,并且根据定制的持久化规则不同,其会不定期的将数据持久化到硬盘中。另外相较于其他的NoSql数据库,redis提供了非常丰富的数据结构,如dict,sds,linkedlist,ziplist,set,quicklist,geometry。在这些存储结构的基础上,redis为用户提供了非常丰富的操作选择,如通过zskiplist来达到对某种类型的数据的排序目的,而排序在数据库中是一个非常耗时的操作。

1.redis单例的安装和使用

      redis相对于其他的缓存框架安装非常的方便,只需要从https://redis.io/download下载后解压,进入redis目录之后执行如下命令即安装完成:

make install

这里需要注意的是make是gcc中的一个命令,安装之前请确保机器安装了gcc。redis中所有的命令都在redis安装目录中的src子目录下,其中比较重要的是redis-server,redis-sentinel,redis-cli。

      编译完成之后在src目录下执行./redis-server启动redis(启动后可关闭该窗口),然后新开一个窗口,在命令行中执行./redis-cli即可连接启动的redis服务。在其中执行如下命令即可看到编译安装成功了:

127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> get hello
"world"

      这里需要说明的是,按照上述方式启动redis,其使用的ip为本机ip 127.0.0.1,端口为6379,并且其余的配置采用的都是默认配置,相关配置可在redis安装目录下的redis.conf文件中查看。如果需要按照指定的配置文件来启动,可在redis-server后接上配置文件名,如:

./src/redis-server redis.conf

另外,上述使用redis-cli连接redis客户端时如果不带任何参数,那么其连接的默认ip和端口为127.0.0.1:6379。如果需要连接指定ip和端口的客户端,可以使用如下方式:

./src/redis-cli -h 127.0.0.1 -p 6379

这里-h参数表示连接的ip,-p则表示连接的端口。

      配置好redis之后,我们就可以在redis中执行相关命令来操作数据,关于redis的常用命令,可查看本人的另一篇博客《redis常用命令大全》,其中有比较详细的讲解。

2.redis主从模式的配置

      redis单例提供了一种数据缓存方式和丰富的数据操作api,但是将数据完全存储在单个redis中主要存在两个问题:数据备份和数据体量较大造成的性能降低。这里redis的主从模式为这两个问题提供了一个较好的解决方案。主从模式指的是使用一个redis实例作为主机,其余的实例作为备份机。主机和从机的数据完全一致,主机支持数据的写入和读取等各项操作,而从机则只支持与主机数据的同步和读取,也就是说,客户端可以将数据写入到主机,由主机自动将数据的写入操作同步到从机。主从模式很好的解决了数据备份问题,并且由于主从服务数据几乎是一致的,因而可以将写入数据的命令发送给主机执行,而读取数据的命令发送给不同的从机执行,从而达到读写分离的目的。如下所示主机redis-A分别有redis-B、redis-C、redis-D、redis-E四个从机:

      前面第1点中我们已经介绍了redis单例的配置方式,而上面我们也介绍了主从模式其实也是多个redis实例组成的,因而redis主从模式的配置可以理解为多个不同的redis实例通过一定的配置告知其相互之间的主从关系。而前面已经介绍,每个redis实例都会占用一个本机的端口号,主从模式的配置主要的配置点有两个:当前实例端口号和当前实例是主机还是从机,是从机的话其主机的ip和端口是什么。一般的redis目录下的redis.conf保存的是默认配置,尽量不要对其进行修改,这里我们复制三份redis.conf文件,分别命名为6379.conf,6380.conf和6381.conf,如下是端口为6379的主机的主要配置:

bind 127.0.0.1
port 6379
logfile "6379.log"
dbfilename "dump-6379.rdb"

如下是端口为6380和6381的从机的配置:

bind 127.0.0.1
port 6380
logfile "6380.log"
dbfilename "dump-6380.rdb"
slaveof 127.0.0.1 6379
bind 127.0.0.1
port 6381
logfile "6381.log"
dbfilename "dump-6381.rdb"
slaveof 127.0.0.1 6379

      可以看到,端口为6380和6381的实例被配置为端口为6379的实例的从机。配置完成后使用redis-server分别执行如下命令启动三个实例:

./src/redis-server 6379.conf
./src/redis-server 6380.conf
./src/redis-server 6381.conf

启动之后分别开启开启三个命令行工具分别执行以下命令连接redis实例:

./src/redis-cli -p 6379
./src/redis-cli -p 6380
./src/redis-cli -p 6381

分别在三个命令行工具中执行一个get命令,获取键名为msg的数据,如下所示:

127.0.0.1:6379> get msg
(nil)
127.0.0.1:6380> get msg
(nil)
127.0.0.1:6381> get msg
(nil)

可以看到,在三个redis实例中都不存在键为msg的数据,现在我们在主机6379上设置一个键为msg的数据,如下所示:

127.0.0.1:6379> set msg "hello"
OK

可以看到设置成功了,此时我们在6380和6381的实例上执行get msg的命令,如下所示:

127.0.0.1:6380> get msg
"hello"
127.0.0.1:6381> get msg
"hello"

可以看到,虽然我们只是在6379的实例上设置了msg这条数据,但是在6380和6381的实例上也存有了相应的数据,说明我们成功配置了redis的主从模式。另外,如果不在配置文件中指定主从节点的关系,也可以在启动相关redis实例之后使用slaveof命令来指定当前节点称为某个节点的从节点,如:

127.0.0.1:6380> slaveof 127.0.0.1 6379

3.redis中sentinel配置

      redis主从模式解决了数据备份和单例可能存在的性能问题,但是其也引入了新的问题。由于主从模式配置了三个redis实例,并且每个实例都使用不同的ip(如果在不同的机器上)和端口号,根据前面所述,主从模式下可以将读写操作分配给不同的实例进行从而达到提高系统吞吐量的目的,但也正是因为这种方式造成了使用上的不便,因为每个客户端连接redis实例的时候都是指定了ip和端口号的,如果所连接的redis实例因为故障下线了,而主从模式也没有提供一定的手段通知客户端另外可连接的客户端地址,因而需要手动更改客户端配置重新连接。另外,主从模式下,如果主节点由于故障下线了,那么从节点因为没有主节点而同步中断,因而需要人工进行故障转移工作。

      为了解决这两个问题,在2.8版本之后redis正式提供了sentinel(哨兵)架构。关于sentinel,这里需要说明几个概念:

名词逻辑结构物理结构
主节点redis主服务/数据库一个独立的redis进程
从节点redis从服务/数据库一个独立的redis进程
sentinel节点监控redis数据节点一个独立的sentinel进程
sentinel节点集合若干sentinel节点的抽象集合若干sentinel节点进程
应用方泛指一个或多个客户端一个或多个客户端线程或进程

      每个sentinel节点其实就是一个redis实例,与主从节点不同的是sentinel节点作用是用于监控redis数据节点的,而sentinel节点集合则表示监控一组主从redis实例多个sentinel监控节点的集合,比如有主节点master和从节点slave-1、slave-2,为了监控这三个主从节点,这里配置N个sentinel节点sentinel-1,sentinel-2,...,sentinel-N。如下图是sentinel监控主从节点的示例图:

      从图中可以看出,对于一组主从节点,sentinel只是在其外部额外添加的一组用于监控作用的redis实例。在主从节点和sentinel节点集合配置好之后,sentinel节点之间会相互发送消息,以检测其余sentinel节点是否正常工作,并且sentinel节点也会向主从节点发送消息,以检测监控的主从节点是否正常工作。。前面讲到,sentinel架构的主要作用是解决主从模式下主节点的故障转移工作的。这里如果主节点因为故障下线,那么某个sentinel节点发送检测消息给主节点时,如果在指定时间内收不到回复,那么该sentinel就会主观的判断该主节点已经下线,那么其会发送消息给其余的sentinel节点,询问其是否“认为”该主节点已下线,其余的sentinel收到消息后也会发送检测消息给主节点,如果其认为该主节点已经下线,那么其会回复向其询问的sentinel节点,告知其也认为主节点已经下线,当该sentinel节点最先收到超过指定数目(配置文件中配置的数目和当前sentinel节点集合数的一半,这里两个数目的较大值)的sentinel节点回复说当前主节点已下线,那么其就会对主节点进行故障转移工作,故障转移的基本思路是在从节点中选取某个从节点向其发送slaveof no one(假设选取的从节点为127.0.0.1:6380),使其称为独立的节点(也就是新的主节点),然后sentinel向其余的从节点发送slaveof 127.0.0.1 6380命令使它们重新成为新的主节点的从节点。重新分配之后sentinel节点集合还会继续监控已经下线的主节点(假设为127.0.0.1:6379),如果其重新上线,那么sentinel会向其发送slaveof命令,使其成为新的主机点的从节点,如此故障转移工作完成。

      上面我们讲到了,每个sentinel节点在本质上还是一个redis实例,只不过和redis数据节点不同的是,其主要作用是监控redis数据节点。在redis安装目录下有个默认的sentinel配置文件sentinel.conf,和配置主从节点类似,这里复制三个配置文件:sentinel-26379.conf,sentinel-26380.conf和sentinel-26381.conf。分别按照如下示例编辑这三个配置文件:

port 26379  
daemonize yes  
logfile "26379.log"  
dir /opt/soft/redis/data  
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000  
sentinel parallel-syncs mymaster 1  
sentinel failover-timeout mymaster 180000
sentinel myid mm55d2d712b1f3f312b637f9b546f00cdcedc787

对于端口为26380和26381的sentinel,其配置和上述类似,只需要把相应的端口号修改为对应的端口号即可。这里注意两点:①每个sentinel的myid参数也要进行修改,因为sentinel之间是通过该属性来唯一区分其他sentinel节点的;②参数中sentinel monitor mymaster 127.0.0.1 6379 2这里的端口号6379是不用更改的,因为sentinel是通过检测主节点的状态来得知当前主节点的从节点有哪些的,因而设置为主节点的端口号即可。配置完成后我们首先启动三个主从节点,然后分别使用三个配置文件使用如下命令启用sentinel:

./src/redis-sentinel sentinel-26379.conf
./src/redis-sentinel sentinel-26380.conf
./src/redis-sentinel sentinel-26381.conf

由于sentinel节点也是一个redis实例,因而我们可以通过如下命令使用redis-cli连接sentinel节点:

./src/redis-cli -p 26379

连上sentinel节点之后我们可以通过如下命令查看sentinel状态:

127.0.0.1:26379> info sentinel

结果如下:

# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=3

可以看到,sentinel检测到主从节点总共有三个,其中一个主节点,两个从节点,并且sentinel节点总共也有三个。启动完成之后,我们可以通过主动下线主节点来模拟sentinel的故障转移过程。首先我们连接上端口为6379的主节点,使用如下命令查看主从节点状态:

127.0.0.1:6379> info replication

结果如下:

# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=45616,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=45616,lag=1
master_repl_offset:45616
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:45615

可以看到,当前主节点有两个从节点,端口分别为6380和6381。然后我们对主节点执行如下命令:

127.0.0.1:6379> shutdown save

然后我们连接上端口号为6380的从节点,并执行如下命令:

127.0.0.1:6380> info replication 

结果如下:

# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=12344,lag=0
master_repl_offset:12477
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:12476

可以看到,当端口为6379的实例下线之后,端口为6380的实例被重新竞选为新的主节点,并且端口为6381的实例被设置为6380的实例的从节点。如果我们此时重新启用端口为6379的节点,然后再查看主从状态,结果如下:

# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=59918,lag=0
slave1:ip=127.0.0.1,port=6379,state=online,offset=59918,lag=1
master_repl_offset:60051
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:60050

可以看到,端口为6379的redis实例重新连接后,sentinel节点检测到其重新连接,那么对其发送命令,使其成为新的主节点的从节点。

4.redis集群的配置

      redis集群是在redis 3.0版本推出的一个功能,其有效的解决了redis在分布式方面的需求。当遇到单机内存,并发和流量瓶颈等问题时,可采用Cluster方案达到负载均衡的目的。并且从另一方面讲,redis中sentinel有效的解决了故障转移的问题,也解决了主节点下线客户端无法识别新的可用节点的问题,但是如果是从节点下线了,sentinel是不会对其进行故障转移的,并且连接从节点的客户端也无法获取到新的可用从节点,而这些问题在Cluster中都得到了有效的解决。

      redis集群中数据是和槽(slot)挂钩的,其总共定义了16384个槽,所有的数据根据一致哈希算法会被映射到这16384个槽中的某个槽中;另一方面,这16384个槽是按照设置被分配到不同的redis节点上的,比如启动了三个redis实例:cluster-A,cluster-B和cluster-C,这里将0-5460号槽分配给cluster-A,将5461-10922号槽分配给cluster-B,将10923-16383号槽分配给cluster-C(总共有16384个槽,但是其标号类似数组下标,是从0到16383)。也就是说数据的存储只和槽有关,并且槽的数量是一定的,由于一致hash算法是一定的,因而将这16384个槽分配给无论多少个redis实例,对于确认的数据其都将被分配到确定的槽位上。redis集群通过这种方式来达到redis的高效和高可用性目的。

      这里需要进行说明的一点是,一致哈希算法根据数据的key值计算映射位置时和所使用的节点数量有非常大的关系。一致哈希分区的实现思路是为系统中每个节点分配一个token,范围一般在0~2^32,这些token构成一个哈希环,数据读写执行节点查找操作时,先根据key计算hash值,然后顺时针找到第一个大于等于该hash值的token节点,需要操作的数据就保存在该节点上。通过分析可以发现,一致哈希分区存在如下问题:

  1. 加减节点会造成哈希环中部分数据无法命中,需要手动处理或忽略这部分数据;
  2. 当使用少量节点时,节点变化将大范围影响环中数据映射,因此这种方式不适合少量节点的分布式方案;
  3. 普通的一致性哈希分区在增减节点时需要增加一倍或减去一半节点才能保证数据和负载的平衡。

正是由于一致哈希分区的这些问题,redis使用了虚拟槽来处理分区时节点变化的问题,也即将所有的数据映射到16384个虚拟槽位上,当redis节点变化时数据映射的槽位将不会变化,并且这也是redis进行节点扩张的基础。

      对于redis集群的配置,首先将redis安装目录下的redis.conf文件复制六份,分别取名为:cluster-6379.conf、cluster-6380.conf、cluster-6381.conf、cluster-6382.conf、cluster-6383.conf、cluster-6384.conf。对于一个高可用的集群方案,集群每个节点都将为其分配一个从节点,以防止数据节点因为故障下线,这里使用六份配置文件定义六个redis实例,其中三个作为主节点,剩余三个分别作为其从节点。对于这六份配置文件,以其中一份为例,以下是其需要修改的参数:

port 6379
cluster-enabled yes
cluster-node-timeout 15000
cluster-config-file "nodes-6379.conf"
pidfile /var/run/redis_6379.pid
logfile "cluster-6379.log"
dbfilename dump-cluster-6379.rdb
appendfilename "appendonly-cluster-6379.aof"

对于其余的配置文件,只需要将其中对应项的端口号和带有端口号的文件名修改为当前要指定的端口号和端口号的文件名即可。配置文件配置好之后使用如下命令启动集群中的每个实例:

./src/redis-server cluster-6379.conf
./src/redis-server cluster-6380.conf
./src/redis-server cluster-6381.conf
./src/redis-server cluster-6382.conf
./src/redis-server cluster-6383.conf
./src/redis-server cluster-6384.conf

仔细阅读上述配置文件可发现,当前配置和启动过程中并没有指定这六个实例的主从关系,也没有对16384个槽位进行分配。因而我们还需要进行进一步的配置,槽位的分配和主从关系的设定有两种方式进行,一种是使用redis-cli连接到集群节点上后使用cluster meet命令连接其他的节点,如我们首先执行如下命令连接到6379端口的节点:

./src/redis-cli -p 6379

连接上后使用cluster meet命令分别连接其余节点:

127.0.0.1:6379>cluster meet 127.0.0.1 6380
127.0.0.1:6379>cluster meet 127.0.0.1 6381
127.0.0.1:6379>cluster meet 127.0.0.1 6382
127.0.0.1:6379>cluster meet 127.0.0.1 6383
127.0.0.1:6379>cluster meet 127.0.0.1 6384 

连接好后可以使用cluster nodes命令查看当前集群状态:

127.0.0.1:6379> cluster nodes
4fa7eac4080f0b667ffeab9b87841da49b84a6e4 127.0.0.1:6384 master - 0 1468073975551 5 connected
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master - 0 0 0 connected
be9485a6a729fc98c5151374bc30277e89a461d8 127.0.0.1:6383 master - 0 1468073978579 4 connected
40622f9e7adc8ebd77fca0de9edfe691cb8a74fb 127.0.0.1:6382 master - 0 1468073980598 3 connected
8e41673d59c9568aa9d29fb174ce733345b3e8f1 127.0.0.1:6380 master - 0 1468073974541 1 connected
40b8d09d44294d2e23c7c768efc8fcd153446746 127.0.0.1:6381 master - 0 1468073979589 2 connected

可以看到配置的六个节点都已经加入到了集群中,但是其现在还不能使用,因为还没有将16384个槽分配到集群节点中。虚拟槽的分配可以使用redis-cli分别连接到6379,6380和6381端口的节点中,然后分别执行如下命令:

127.0.0.1:6379>cluster addslots {0...5461}
127.0.0.1:6380>cluster addslots {5462...10922}
127.0.0.1:6381>cluster addslots {10923...16383}

添加完槽位后可使用cluster info命令查看当前集群状态:

127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_sent:4874
cluster_stats_messages_received:4726 

这里我们将16384个虚拟槽位分配给了三个节点,而剩余的三个节点我们通过如下命令将其配置为这三个节点的从节点,从而达到高可用的目的:

127.0.0.1:6382>cluster replicate cfb28ef1deee4e0fa78da86abe5d24566744411e
OK
127.0.0.1:6383>cluster replicate 8e41673d59c9568aa9d29fb174ce733345b3e8f1
OK
127.0.0.1:6384>cluster replicate 40b8d09d44294d2e23c7c768efc8fcd153446746
OK 

如此,所有的集群节点都配置完毕,并且处于可用状态。这里可以使用cluster nodes命令查看当前节点的状态:

127.0.0.1:6379> cluster nodes
4fa7eac4080f0b667ffeab9b87841da49b84a6e4 127.0.0.1:6384 slave 40b8d09d44294d2e23c7c768efc8fcd153446746 0 1468076865939 5 connected
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master - 0 0 0 connected 0-5461
be9485a6a729fc98c5151374bc30277e89a461d8 127.0.0.1:6383 slave 8e41673d59c9568aa9d29fb174ce733345b3e8f1 0 1468076868966 4 connected
40622f9e7adc8ebd77fca0de9edfe691cb8a74fb 127.0.0.1:6382 slave cfb28ef1deee4e0fa78da86abe5d24566744411e 0 1468076869976 3 connected
8e41673d59c9568aa9d29fb174ce733345b3e8f1 127.0.0.1:6380 master - 0 1468076870987 1 connected 5462-10922
40b8d09d44294d2e23c7c768efc8fcd153446746 127.0.0.1:6381 master - 0 1468076867957 2 connected 10923-16383

我们使用redis-cli使用如下命令连接集群:

./src/redis-cli -c -p 6380

注意连接集群模式的redis实例时需要加上参数-c,表示连接的是集群模式的实例。连接上后执行get命令:

127.0.0.1:6380> get hello
-> Redirected to slot [866] located at 127.0.0.1:6379
(nil)

可以看到,在6380端口的实例上执行get命令时,其首先会为当前的键通过一致哈希算法计算其所在的槽位,并且判断该槽位不在当前redis实例中,因而重定向到目标实例上执行该命令,最后发现没有该键对应的值,因而返回了一个(nil)。

 

手把手教您同花顺如何设置大盘分时均价线 本文将手把手教你如何在同花顺PC端开启大盘指数分时图📈 阅读详情

相关推荐

Unity游戏接入穿山甲广告SDK全攻略:从零到上线的避坑指南

本文为Unity开发者提供了接入穿山甲广告SDK的完整实战指南。详细解析了从账号注册、应用创建到Unity插件集成、安卓与iOS平台打包配置的全流程,并重点分享了广告加载失败、展示异常等常见问题的排查与解决方案,帮助开发者高效实现游戏广告变现。

weixin_29015899的博客 536

在Spring Boot微服务使用JedisCluster操作Redis集群Hash哈希散列

记录:451 场景:在Spring Boot微服务使用JedisCluster操作Redis集群的Hash哈希散列数据类型。

zhangbeizhen18的博客 2083

4. PCIe 接口时序

在上一篇中,大致介绍IPcore接口。总的来说接口如下图数据的接收和发送通过transmitTLPinterface和ReceiveTLPinterface。收发数据的时序也只是描述这几个接口的关系。从手册上截取PCIex1的接口时序。

jjinl的专栏 6123

windows--Redis集群搭建和Jedis连接

一、Redis集群搭建 1.下载redis 2.创建集群的端口分别为6380,6381,6382,将下载好的redis内容复制到创建的文件夹下 以6380文件夹为例: 在每个文件内创建一个启动脚本start.bat # 6380为创建的端口 title redis-6380 redis-server.exe redis.windows.conf 3.修改里面的配置文件redis.windows.conf port 6380 //修改为与当前文件夹名字一样的端口号 appe.

YP~杨小西 1065

鸿蒙实战开发教程-注册登录页面

在密码输入框中,只要设置TextInput的类型就可以实现带眼睛logo的密码输入框效果:

2401_82546228的博客 3561

20 硬件工程师笔面试高频考点真题解析——寄存器

摘要: 寄存器是由多个边沿触发的D触发器组成的多位存储单元,用于同步时序电路中的数据暂存、隔离毛刺、跨时钟域同步等。选型需考虑位宽、触发方式(边沿/电平)、异步控制、电气参数等。核心时序参数包括建立时间(Tsu)、保持时间(Thold)和时钟输出延迟(Tco)。寄存器广泛应用于时序逻辑、流水线分割、毛刺消除、跨时钟域同步及计数分频等场景。同步复位依赖时钟边沿,时序易收敛但需时钟支持;异步复位独立于时钟,上电可靠但需注意亚稳态风险。

XU157303764的博客 1342

JedisCluster如何添加keys方法-walker小飞java博客

JedisCluster如何添加keys方法 需求:目前项目是老项目,还是使用的jedisCluster,发现里面根本不支持keys方法,大家也知道keys方法数据量大会有性能问题,但是我这边有一个场景,实时获取到用户的在线状态,我这边会把某个前缀的redis中的key提取出来,然后在做一定的逻辑修改,大家可以复制过去直接用。 步骤: 1.为了扩展JedisCluster大家可以单独弄一个接口出来。 代码: public interface JedisClusterService { JedisPool g

qq_25674251的博客 1008

模型预测控制(MPC)解析(二):单输入单输出系统

在上一篇中,为了便于说明,预测控制系统采用单输入单输出系统为例进行设计。由于系统模型使用的是状态空间方程,于是可以很容易的将这种设计方法可以扩展到多输入、多输出系统。

行者无疆的博客 8224

java redis集群操作,java操作redis3.0集群

java(JedisCluster)操作redis集群这里只是几个简单的demo,直接上代码吧,没啥好说的123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778...

weixin_32252533的博客 825

SAP Joule 在顾问与开发者场景的双擎定位:Joule for Consultants 与 Joule for Developers 全面解读

SAP推出企业级AI助手Joule,分为顾问版(Joule for Consultants)和开发者版(Joule for Developers)两个版本。顾问版聚焦咨询业务,整合SAP知识库和方法论,辅助方案设计、差距分析和实施落地;开发者版嵌入开发工具链,支持代码生成、解释、测试和迁移。两者共享智能底座但面向不同场景:顾问版优化项目交付流程,开发者版提升工程效率。典型案例显示,Joule能有效缩短云转型周期,实现从业务咨询到技术落地的无缝衔接。该产品通过AI代理和知识图谱技术,为企业数字化转型提供端到端

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 355

2025年微信小程序获取手机号授权登录注册详细教程(含服务端)。不弹窗原因以及减少组件用量的方法

前端把获取到的code传给后端,后端获取access_token和前端传过来的code,请求服务器接口,即可获取到手机号。

coderYYY的博客 3万+

使用jedisCluster操作Redis集群

      连接单机版 第一步:创建一个Jedis对象。需要指定服务端的ip及端口。 第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。 第三步:打印结果。 第四步:关闭Jedis @Test public void testJedis()throws Exception { // 第一步:创建一个Jedis对象。需要指定服务端的ip及端口。 Jedis...

ycmnzmm的博客 1万+

儿童启蒙教育APP

pinyinList.add(createPinyin("a", "啊,像阿姨的阿", R.raw.pinyin_a));pinyinList.add(createPinyin("i", "衣,像衣服的衣", R.raw.pinyin_i));pinyinList.add(createPinyin("u", "乌,像乌鸦的乌", R.raw.pinyin_u));pinyinList.add(createPinyin("ü", "鱼,像小鱼的鱼", R.raw.pinyin_v));-- 固定竖屏 -->

寒寒豆豆软件公司的博客 168

RedisCluster搭建及原理详解

由于数据量过大,单个Master复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展每个复制集只负责存储整个数据集的一部分,这就是Redis的集群,其作用是提供在多个Redis节点间共享数据的程序集。Redis集群是一种通过将多个Redis节点连接在一起以实现高可用性、数据分片和负载均衡的技术。它允许Redis在不同节点上同时提供服务,提高整体性能和可靠性。Redis集群主要有三种模式:主从复制模式(Master-Slave)、哨兵模式(Sentinel)、Cluster模式。

dys000000的博客 1639

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

RedisCluster集群扩容

整个集群运行正常,三个master节点和三个slave节点,8001端口的实例节点存储0-5460这些hash槽,8002端口的实例节点存储5461-10922这些hash槽,8003端口的实例节点存储10923-16383这些hash槽,这三个master节点存储的所有hash槽组成redis集群的存储槽位,slave点是每个主节点的备份从节点,不显示存储槽位!的add-node命令新增一个主节点8007(master),前面的ip:port为新增节点,后面的ip:port为集群中已存在的节点。

qq_32486597的博客 1372

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

SpringMVC rediscluster 配置

redis相关学习资料:https://edu.51cto.com/video/4196.htmlSpringMVC RedisCluster 配置指南 作为一名刚入行的开发者,你可能会对如何在SpringMVC项目中配置RedisCluster感到困惑。不用担心,我将通过这篇文章,为你详细讲解整个配置流程。 配置流程 ...

weixin_36374366的博客 248

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Redis之RedisCluster集群

Redis之Redis Cluster的使用 一、Redis Cluster 简介 Redis Sentinel 水平扩容一直都是一个痛点,因为水平扩容牵涉到数据的迁移。迁移过程一方面要保证自己的业务是可用的,一方面要保证尽量不丢失数据所以数据能不迁移就尽量不迁移。针对这个问题,Redis Cluster就应运而生了。 Redis Cluster 是 Redis 的分布式解决方案,在3.0版本正式...

学习和工作总结,共勉! 482

RedisCluster路由

org.redisson.cluster.ClusterConnectionManager#addMasterEntry初始化slot和node的映射关系存储在。)连接redis主节点,存取键值时redis-cli同样也会接收到MOVED重定向错误,但是会自动根据重定向信息来切换节点重新发起请求。在ClusterConnectionManager中的slot2entry中, 根据key所对应的slot获取对应的节点信息。使用redis-cli客户端普通连接redis主节点,来存取键值会返回。

慢慢来~ 510

RedisCluster扩容

已经有一篇文章写关于rediCluster的部署和启动 RedisCluster的安装、部署 这篇记录RedisCluster扩容 一、创建新目录 cd /var/redisCluster/ 创建新的7007文件 mkdir 7007 进入到redi安装目录;(/var/redis-5.0.5/src),执行一下命令 make install PREFIX=/var/redisCluster/7007 然后执行复制redis.conf cp /var/redis-5.0.5/redis.conf /v

没有眉毛的阿斗叶 247

RedisCluster 集群实现原理

文章目录1. Redis Cluster 的架构RedisCluster 设计成 16384 个 Slot 的原因2. 集群内部通信机制2.1 RedisCluster 节点间通信方式2.2 Gossip 协议3. 高可用性原理 1. Redis Cluster 的架构 从 redis 3.0 版本之后,redis 支持 Redis-Cluster集群作为 Redis 的分布式解决方案。该集群采用多主多从结构,使用多个 Master节点保存数据和整个集群状态,这样就可以很好地支持横向扩容,通过增减 Mast

谈谈1974 1453

14-RedisCluster

Redis Cluster 集群 简介 为了提供高可用高并发的水平拓展,就必须采用集群。 一组Redis Cluster是由多个Redis实例组成,官方推荐我们使用6实例,其中3个为主节点,3个为从结点。一旦有主节点发生故障的时候,Redis Cluster可以选举出对应的从结点成为新的主节点,继续对外服务,从而保证服务的高可用性。 Redis Cluster 把所有的数据划分为16384个不同的槽位,可以根据机器的性能把不同的槽位分配给不同的Redis实例,对于Redis实例来说,他们只会存储部门的Red

qq_35752835的博客 431

php redis集群 RedisCluster类

<?php /** * Helper autocomplete for php redis cluster extension. * Based on the phpredis-phpdoc by Max Kamashev (https://github.com/ukko/phpredis-phpdoc) * * @author Tommy Zheng <tommy@vlv...

IT小学生 2643

RedisCluster集群扩容与缩容

目录一、传统Redis集群存在那些问题二、传统RedisCluster集群的原理三、RedisCluster集群模式环境搭建四、RedisCluster集群模式扩容节点五、RedisCluster集群模式缩容节点 一、传统Redis集群存在那些问题 Redis哨兵集群模式,每个节点都保存全量同步数据,冗余的数据比较多;而在Redis Cluster模式中集群中采用分片集群模式,可以减少冗余数据,缺点就是构建该集群模式成本非常高, 二、传统RedisCluster集群的原理 Redis3.0开始官方推出了集群

记录各种Bug解决案例及日常学习内容 1358

碾压阿里面试官,RedisCluster集群全网最全知识点

为什么需要集群 并发量 redis 本身 10w/s,如果业务需要100 w/s 呢? 数据量 一个 redis 及其内存 16~256G,如果业务需要 500G 呢? 不止于加机器。 RedisCluster在 3.0 发布。 5 一致性哈希 6 虚拟槽哈希分区(Redis Cluster所采用) 7 Redis Cluster基本架构 8 Redis Cluster 安装配置 Redis 3.0之后,节点之间通过去中心化的方式,提供了完整

JavaEdge全是干货的技术号 3519

PhpRedis终极指南:Redis、RedisCluster与RedisSentinel三大核心类深度解析

PhpRedis是一个功能强大的PHP扩展,为PHP应用程序提供了与Redis数据库的高效交互能力。它支持Redis的核心功能、集群模式和哨兵机制,通过Redis、RedisCluster和RedisSentinel三大核心类,帮助开发者轻松构建高性能、高可用的分布式应用。本指南将带你全面了解这三个核心类的使用方法和最佳实践。 ## 一、Redis类:PHP与Redis的基础交互桥梁 Redi

gitblog_00851的博客 1087

20191225 RedisCluster

RedisCluster原理 整个缓存查询命中率。 一致性Hash正是为了解决这个问题而出现的,该路由算法通过引入一个一致性Hash环,以及进一步增加虚拟节点层,来实现尽可能高的命中率。 使用FNV1_32_HASH哈希算法来尽可能使key与节点分布得更加均匀,引入了虚拟节点,来做负载均衡。 集群内部通信 在redis cluster集群内部通过gossip协议进行通信,集群元数据...

陈如水的专栏 583
上一篇: 使用ZooKeeper实现Java跨JVM的分布式锁(读写锁)
下一篇: HTTPS 原理解析
王树民
博客等级 码龄10年 912粉丝 560原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值