Redis5.0.10单机伪集群搭建

1、Redis集群概述

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

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 ,比如set k1 v1 ,按照Redis cluster的哈希槽算法:CRC16(‘k1’)%16384 = 2412。 那么就会把这个key 的存储分配到 A 上了。同样,当我连接(A,B,C)任何一个节点想获取k1这个key时,也会这样的算法,然后内部跳转到A节点上获取数据。这种哈希槽的分配方式有好也有坏,好处就是很清晰,比如我想新增一个节点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 为了保证数据的高可用性,加入了主从模式,一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是从主节点拉取数据备份,当这个主节点挂掉后,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉。举个例子,集群有A、B、C三个主节点,各自从节点为A1、B1、C1,那么如果C主节点挂掉了,C1结点就会自动代替上,变成主节点。所以我们在集群建立的时候,一定要为每个主节点都添加了从节点,从而达到高可用性。如果C节点和C1节点同时挂掉了,那么这个集群也会挂掉。

2、搭建集群

1、安装Redis

这里我就不多说什么了,参考:Redis学习(一)----简介与安装

2、修改配置,创建节点

我们进入Redis的安装目录,先创建redis_cluster目录,然后再分别在redis_cluster下创建7001、7002、7003、7004、7005、7006这6个目录。

Redis5.0.10单机伪集群搭建

然后将redis解压目录下的redis.conf配置文件复制过来。

Redis5.0.10单机伪集群搭建

将六个节点的 redis.conf 配置文件进行修改 ,修改以下几个:

  1. port 7001:六个节点配置文件分别是7001-7006
  2. daemonize yes:redis后台运行
  3. pidfile /var/run/redis_7001.pid:pidfile文件对应7001-7006
  4. logfile "7001.log":日志文件
  5. cluster-enabled yes:开启集群
  6. cluster-config-file nodes_7001.conf:保存节点配置,自动创建,更新对应7001-7006
  7. cluster-node-timeout 5000:集群超时时间,节点超过这个时间没反应就断定是宕机

①、修改端口

Redis5.0.10单机伪集群搭建

②、让redis以守护进程的方式运行,将 daemonize 改成yes

Redis5.0.10单机伪集群搭建

③、修改pidfile文件

Redis5.0.10单机伪集群搭建

④、修改日志文件

Redis5.0.10单机伪集群搭建

⑤、 开启集群,打开注释cluster-enabled yes,这里必须打开,很重要。

Redis5.0.10单机伪集群搭建

⑥、 保存节点配置

Redis5.0.10单机伪集群搭建

⑦、设置集群超时时间

Redis5.0.10单机伪集群搭建

分别将7001-7006配置一遍。 

3、编写Redis集群启动脚本

编写集群的启动和停止shell脚本,这样方便:

vi  start.sh  加入下面内容:

/usr/local/redis/bin/redis-server /usr/local/redis/redis_cluster/7001/redis.conf
/usr/local/redis/bin/redis-server /usr/local/redis/redis_cluster/7002/redis.conf
/usr/local/redis/bin/redis-server /usr/local/redis/redis_cluster/7003/redis.conf
/usr/local/redis/bin/redis-server /usr/local/redis/redis_cluster/7004/redis.conf
/usr/local/redis/bin/redis-server /usr/local/redis/redis_cluster/7005/redis.conf
/usr/local/redis/bin/redis-server /usr/local/redis/redis_cluster/7006/redis.conf

vi stop.sh 加入下面内容:

/usr/local/redis/bin/redis-cli -p 7001 shutdown
/usr/local/redis/bin/redis-cli -p 7002 shutdown
/usr/local/redis/bin/redis-cli -p 7003 shutdown
/usr/local/redis/bin/redis-cli -p 7004 shutdown
/usr/local/redis/bin/redis-cli -p 7005 shutdown
/usr/local/redis/bin/redis-cli -p 7006 shutdown

修改权限:

chmod 755  start.sh stop.sh

Redis5.0.10单机伪集群搭建

然后启动所有节点

Redis5.0.10单机伪集群搭建

4、启动集群

注意:在启动集群的时候redis数据库必须是空的,否则会报错提示:[ERR] Node 127.0.0.1:7001 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0。

解决方法:删除生成的配置文件nodes.conf,如果不行则说明现在创建的结点包括了旧集群的结点信息,需要删除redis的持久化文件后再重启redis,比如:appendonly.aof、dump.rdb。

在Redis3.0的版本启动集群使用的命令是:redis-trib.rb create --replicas 1  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 127.0.0.1:7006  ,Redis官方提供了redis-trib.rb工具,但是在使用之前需要安装ruby,以及redis和ruby连接工具。

但是Redis5.0集群管理工具redis-trib.rb已经被废弃,所以不用安装ruby啥的了,现在已经集成到了redis-cli中,并且可以在有认证的情况执行了,可以通过redis-cli --cluster help查看使用方式。

[root@localhost redis_cluster]# cd /usr/local/redis/bin/
[root@localhost bin]# ./redis-cli --cluster help
Cluster Manager Commands:
  create         host1:port1 ... hostN:portN
                 --cluster-replicas <arg>
  check          host:port
                 --cluster-search-multiple-owners
  info           host:port
  fix            host:port
                 --cluster-search-multiple-owners
  reshard        host:port
                 --cluster-from <arg>
                 --cluster-to <arg>
                 --cluster-slots <arg>
                 --cluster-yes
                 --cluster-timeout <arg>
                 --cluster-pipeline <arg>
                 --cluster-replace
  rebalance      host:port
                 --cluster-weight <node1=w1...nodeN=wN>
                 --cluster-use-empty-masters
                 --cluster-timeout <arg>
                 --cluster-simulate
                 --cluster-pipeline <arg>
                 --cluster-threshold <arg>
                 --cluster-replace
  add-node       new_host:new_port existing_host:existing_port
                 --cluster-slave
                 --cluster-master-id <arg>
  del-node       host:port node_id
  call           host:port command arg arg .. arg
  set-timeout    host:port milliseconds
  import         host:port
                 --cluster-from <arg>
                 --cluster-copy
                 --cluster-replace
  help           

For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.

[root@localhost bin]# 

启动集群,直接一个命令就OK:

./redis-cli --cluster create 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 127.0.0.1:7006 --cluster-replicas 1

Redis5.0.10单机伪集群搭建

Redis5.0.10单机伪集群搭建

从上面的运行结果看,默认给的 主节点就是7001 7002 7003 ,从节点分别是7004 7005 7006 (三主三从

  • 7001分配到的哈希槽是 0-5460
  • 7002分配到的哈希槽是 5461-10922
  • 7003分配到的哈希槽是 10923-16383

这样16384个卡槽全部分配完毕,集群创建成功,可以使用了。

5、添加主从节点到集群中

我们新建两个目录7007、7008用于给集群添加一个主从节点:

Redis5.0.10单机伪集群搭建

同样的方法修改7007、7008的 redis.conf 配置文件。然后启动它们:

Redis5.0.10单机伪集群搭建

启动成功。

①、添加Master主节点

注意:在启动集群的时候redis数据库必须是空的,否则会报错提示:[ERR] Node 127.0.0.1:7001 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0。

解决方法:删除生成的配置文件nodes.conf,如果不行则说明现在创建的结点包括了旧集群的结点信息,需要删除redis的持久化文件后再重启redis,比如:appendonly.aof、dump.rdb。

./redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001

Redis5.0.10单机伪集群搭建

然后查看redis集群信息:

./redis-cli --cluster check 127.0.0.1:7001

Redis5.0.10单机伪集群搭建

可以看到 7007端口作为master 主节点加入到redis集群中 ,但 7007 没有slots卡槽

使用下面命令为7007端口增加卡槽:

./redis-cli --cluster reshard 127.0.0.1:7007

Redis5.0.10单机伪集群搭建

然后查看分配卡槽的信息:

Redis5.0.10单机伪集群搭建

分配成功!

②、添加Slave节点

我们给Master主节点7007添加一个从节点7008:

# 127.0.0.1:7008         节点的ip和端口
# 127.0.0.1:7001         已存在集群中的一个节点ip和端口  
# add-node               添加一个节点 
# --cluster-slave        从节点
# --cluster-master-id    该从节点的master节点id 

./redis-cli --cluster add-node 127.0.0.1:7008 127.0.0.1:7001 --cluster-slave --cluster-master-id e3ed175cd38c9ea5b7a0827f2be7b8bfa9385ba2

Redis5.0.10单机伪集群搭建

然后查看集群的信息:

./redis-cli --cluster check 127.0.0.1:7001

Redis5.0.10单机伪集群搭建

可以发现7008端口已经成为了7007端口的从节点。

③、删除 slave从节点

./redis-cli --cluster del-node 127.0.0.1:7008 609e99ae01ce067323f8c44207f512b5cd3546e2

Redis5.0.10单机伪集群搭建

成功删除7008从节点。

④、删除Master主节点

要删除master节点,首先要将它的 slot卡槽全部提取到别的master节点上:

./redis-cli --cluster reshard 127.0.0.1:7001

Redis5.0.10单机伪集群搭建

查看一下集群信息:

Redis5.0.10单机伪集群搭建

此时7007节点上的slot卡槽已经是0个了:

如果想卡槽分配均匀,可以使用如下命令:

./redis-cli --cluster rebalance --cluster-threshold 1 127.0.0.1:7001

删除 7007 master节点

./redis-cli --cluster del-node 127.0.0.1:7007 73f19b384906113507b25f256a781ce184777162

./redis-cli --cluster check 127.0.0.1:7001

Redis5.0.10单机伪集群搭建

删除成功。

6、集群数据测试

我们先连接Redis任意一个节点端口:

./redis-cli -c -p 7001    # -c 表示集群 -p是端口

Redis5.0.10单机伪集群搭建

这就是Redis Cluster值分配规则,所以分配key的时候,它会使用CRC16(‘k1’)%16384算法,来计算,将这个key 放到哪个节点,这里分配到了12706 slot 就分配到了7003这个节点上。

我们在其他的节点上也能获取到这个值。

Redis5.0.10单机伪集群搭建

7、集群宕机测试

我们来挂掉一个节点测试一下,如果将7001节点kill掉:

Redis5.0.10单机伪集群搭建

我们再来查看一下集群的信息(./redis-cli --cluster check 127.0.0.1:7002):

Redis5.0.10单机伪集群搭建

可以发现集群并没有挂掉,这是因为7006本来是7001的从节点,结果发现7001节点挂了,然后7006节点顶上去,变成了Master主节点。

那么我们把7006也给它干死,会怎么样呢?

Redis5.0.10单机伪集群搭建

再次查看集群节点信息;

Redis5.0.10单机伪集群搭建

这里发现出现了错误,说有一些 哈希槽没得分配,也说明了Redis集群必须要三个结点才能创建成功!

[ERR] Not all 16384 slots are covered by nodes.  没有安全覆盖;所以不能正常使用集群了;