redis cluster集群详解

前面博客我们已经学习到sentinel问题?为什么还要讲cluster呢?
使用Redis Sentinel 模式架构的缓存体系,在使用的过程中,随着业务的增加不可避免的要对Redis进行扩容,熟知的扩容方式有两种,一种是垂直扩容,一种是水平扩容。垂直扩容表示通过加内存方式来增加整个缓存体系的容量比如将缓存大小由2G调整到4G,这种扩容不需要应用程序支持;水平扩容表示表示通过增加节点的方式来增加整个缓存体系的容量比如本来有1个节点变成2个节点,这种扩容方式需要应用程序支持。垂直扩容看似最便捷的扩容,但是受到机器的限制,一个机器的内存是有限的,所以垂直扩容到一定阶段不可避免的要进行水平扩容,如果预留出很多节点感觉又是对资源的一种浪费因为对业务的发展趋势很快预测。Redis Sentinel 水平扩容一直都是程序猿心中的痛点,因为水平扩容牵涉到数据的迁移。迁移过程一方面要保证自己的业务是可用的,一方面要保证尽量不丢失数据所以数据能不迁移就尽量不迁移。针对这个问题,Redis Cluster就应运而生了,下面简单介绍一下RedisCluster。
Redis Cluster是Redis的分布式解决方案,在Redis 3.0版本正式推出的,有效解决了Redis分布式方面的需求。当遇到单机内存、并发、流量等瓶颈时,可以采用Cluster架构达到负载均衡的目的。分布式集群首要解决把整个数据集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整个数据的一个子集。Redis Cluster采用哈希分区规则中的虚拟槽分区。虚拟槽分区巧妙地使用了哈希空间,使用分散度良好的哈希函数把所有的数据映射到一个固定范围内的整数集合,整数定义为槽(slot)。Redis Cluster槽的范围是0 ~ 16383。槽是集群内数据管理和迁移的基本单位。采用大范围的槽的主要目的是为了方便数据的拆分和集群的扩展,每个节点负责一定数量的槽。Redis Cluster采用虚拟槽分区,所有的键根据哈希函数映射到0 ~ 16383,计算公式:slot = CRC16(key)&16383。每一个实节点负责维护一部分槽以及槽所映射的键值数据。
 

Redis集群

 
 
高性能:
 
基于KEY进行数据拆分
 
1、在多分片节点中,将16384个槽位,均匀分布到多个分片节点中
2、存数据时,将key做crc16(key),然后和16384进行取模,得出槽位值(0-16383之间)
3、根据计算得出的槽位值,找到相对应的分片节点的主节点,存储到相应槽位上
4、如果客户端当时连接的节点不是将来要存储的分片节点,分片集群会将客户端连接切换至真正存储节点进行数据存储
 
高可用:
在搭建集群时,会为每一个分片的主节点,对应一个从节点,实现slaveof的功能,同时当主节点down,实现类似于sentinel的自动failover的功能。
 
Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation)。
Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 Redis 节点之间移动数据, 并且在高负载的情况下, 这些命令将降低 Redis 集群的性能, 并导致不可预测的行为。
Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。
将数据自动切分(split)到多个节点的能力。
当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续处理命令请求的能力。
 

Redis集群数据共享

Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现: 一个 Redis 集群包含 16384 个哈希槽(hash slot), 数据库中的每个键都属于这 16384 个哈希槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。
节点 A 负责处理 0 号至 5500 号哈希槽。
节点 B 负责处理 5501 号至 11000 号哈希槽。
节点 C 负责处理 11001 号至 16384 号哈希槽。
 

槽的计算公式

集群使用公式 CRC16(key) & 16383 计算键 key属于哪个槽。

运行机制

所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
节点的fail是通过集群中超过半数的master节点检测失效时才生效.
客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key
 

集群复制

 
为了使得集群在一部分节点下线或者无法与集群的大多数(majority)节点进行通讯的情况下, 仍然可以正常运作, Redis 集群对节点使用了主从复制功能: 集群中的每个节点都有 1 个至 N 个复制品(replica), 其中一个复制品为主节点(master), 而其余的 N-1 个复制品为从节点(slave)。
  在之前列举的节点 A 、B 、C 的例子中, 如果节点 B 下线了, 那么集群将无法正常运行, 因为集群找不到节点来处理 5501 号至 11000 号的哈希槽。
  假如在创建集群的时候(或者至少在节点 B 下线之前), 我们为主节点 B 添加了从节点 B1 , 那么当主节点 B 下线的时候, 集群就会将 B1 设置为新的主节点, 并让它代替下线的主节点 B , 继续处理 5501 号至 11000 号的哈希槽, 这样集群就不会因为主节点 B 的下线而无法正常运作了。
  不过如果节点 B 和 B1 都下线的话, Redis 集群还是会停止运作。
  集群的复制特性重用了 SLAVEOF 命令的代码,所以集群节点的复制行为和 SLAVEOF 命令的复制行为完全相同。
 
 

集群的故障转移

 
•在集群里面,节点会对其他节点进行下线检测。
•当一个主节点下线时,集群里面的其他主节点负责对下线主节点进行故障移。
•换句话说,集群的节点集成了下线检测和故障转移等类似 Sentinel 的功能。
•因为 Sentinel 是一个独立运行的监控程序,而集群的下线检测和故障转移等功能是集成在节点里面的,它们的运行模式非常地不同,所以尽管这两者的功能很相似,但集群的实现没有重用 Sentinel 的代码。
 
 

在集群里面执行命令的两种情况

 
•命令发送到了正确的节点:命令要处理的键所在的槽正好是由接收命令的节点负责,那么该节点执行命令,就像单机 Redis 服务器一样。
•命令发送到了错误的节点:接收到命令的节点并非处理键所在槽的节点,那么节点将向客户端返回一个转向(redirection)错误,告知客户端应该到哪个节点去执行这个命令,客户端会根据错误提示的信息,重新向正确的节点发送命令。
 

命令发送给正确的节点

键 date 位于 2022 槽,该槽由节点 7000 负责,命令会直接执行。

命令发送给了错误的节点

键 date 位于 2022 槽,该槽由节点 7000 负责,但错误发送到了7001节点

转向错误的实现(1)

集群中的节点会互相告知对方,自己负责处理哪些槽。
 

转向错误的实现(2)

集群中的每个节点都会记录 16384 个槽分别由哪个节点负责,从而形成一个“槽表”(slot table)。
节点在接收到命令请求时,会通过槽表检查键所在的槽是否由本节点处理:
- 如果是的话,那么节点直接执行命令;
- 如果不是的话,那么节点就从槽表里面提取出正确节点的地址信息,然后返回转向错误。
 

redis cluster集群的搭建

规划、搭建过程:
 
6个redis实例,一般会放到3台硬件服务器
注:在企业规划中,一个分片的两个节点,分到不同的物理机,防止硬件主机宕机造成的整个分片数据丢失。

主机名
ip
操作系统
redis版本
实例规划
docker-01
10.0.0.130
centos7.4
5.05稳定版
/data/7000 master
/data/7001 slave
docker-02
10.0.0.131
centos7.4
5.05稳定版
/data/7002 master
/data/7003 slave
docker-03
10.0.0.132
centos7.4
5.05稳定版
/data/7004 master
/data/7005 slave
注意: 每台服务器上的两个实例不能互为主从,否则如果服务器挂掉就会导致集群中一个节点数据的丢失,应该让每台服务器他们彼此互为主从,这里我们规划如下
docker-01 7000 master ---> docker-02 7003 slave
docker-02 7002 master ---> docker-03 7005 slave
docker-03 7004 master ---> docker-01 7001 slave

1. 安装集群插件(redis5不用安装插件)

EPEL源安装ruby支持
yum install ruby rubygems -y
使用国内源
gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
gem install redis -v 3.3.3
gem sources -l
如果无法使用,可以使用aliyun
gem sources -a http://mirrors.aliyun.com/rubygems/
gem sources  --remove http://rubygems.org/
 
注意对于新版redis5 (已经出稳定版了)中已经把这个插件嵌入到了redis-cli中了,无需我们安装这个插件。下面为官方的说明:
如果您使用的是Redis 5,这很容易实现,因为嵌入到中的Redis Cluster命令行实用程序redis-cli将为我们提供帮助,该实用程序可用于创建新集群,检查或重新分片现有集群等。

2. 集群节点的准备

 
在每一个服务器节点安装规划创建好目录
mkdir /data/700{0..5}
 
vim /data/7000/redis.conf
port 7000
daemonize yes
pidfile /data/7000/redis.pid
loglevel notice
logfile "/data/7000/redis.log"
dbfilename dump.rdb
dir /data/7000
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

  

vim /data/7001/redis.conf
port 7001
daemonize yes
pidfile /data/7001/redis.pid
loglevel notice
logfile "/data/7001/redis.log"
dbfilename dump.rdb
dir /data/7001
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

 

vim /data/7002/redis.conf
port 7002
daemonize yes
pidfile /data/7002/redis.pid
loglevel notice
logfile "/data/7002/redis.log"
dbfilename dump.rdb
dir /data/7002
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

  

vim /data/7003/redis.conf
port 7003
daemonize yes
pidfile /data/7003/redis.pid
loglevel notice
logfile "/data/7003/redis.log"
dbfilename dump.rdb
dir /data/7003
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

  

vim /data/7004/redis.conf
port 7004
daemonize yes
pidfile /data/7004/redis.pid
loglevel notice
logfile "/data/7004/redis.log"
dbfilename dump.rdb
dir /data/7004
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

  

vim /data/7005/redis.conf
port 7005
daemonize yes
pidfile /data/7005/redis.pid
loglevel notice
logfile "/data/7005/redis.log"
dbfilename dump.rdb
dir /data/7005
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
 
Redis 集群由多个运行在集群模式(cluster mode)下的 Redis 实例组成, 实例的集群模式需要通过配置来开启, 开启集群模式的实例将可以使用集群特有的功能和命令。
以下是一个包含了最少选项的集群配置文件示例:
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

  

3. 启动节点并验证

redis-server /data/7000/redis.conf 
redis-server /data/7001/redis.conf 
redis-server /data/7002/redis.conf 
redis-server /data/7003/redis.conf 
redis-server /data/7004/redis.conf 
redis-server /data/7005/redis.conf 

[root@docker-01 ~]# ps -ef|grep -v grep |grep redis
root      74891      1  0 07:15 ?        00:00:01 redis-server *:7000 [cluster]
root      75699      1  0 07:16 ?        00:00:00 redis-server *:7001 [cluster]

[root@docker-02 ~]# ps -ef|grep -v grep |grep redis
root       6411      1  0 07:17 ?        00:00:00 redis-server *:7002 [cluster]
root       6416      1  0 07:17 ?        00:00:00 redis-server *:7003 [cluster]

[root@docker-03 ~]# ps -ef|grep -v grep |grep redis
root      17074      1  0 07:17 ?        00:00:00 redis-server *:7004 [cluster]
root      17079      1  0 07:18 ?        00:00:00 redis-server *:7005 [cluster]

  

4. 创建集群(将节点加入集群)

redis-cli --cluster create --cluster-replicas 1 10.0.0.130:7000 10.0.0.131:7002 10.0.0.132:7004 10.0.0.131:7003 10.0.0.132:7005 10.0.0.130:7001
给定 redis-cli 程序的命令是 create , 这表示我们希望创建一个新的集群。
选项 --replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。
创建时会自动把前面三个节点作为主节点,后面三个作为从节点, 主节点和从节点一一对应
 
redis3建集群的命令(reidis5已经把这个插件集成到了redis-cli中了)
{redis_src_home}/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
 
 
主从对应刚好跟我们预想的一样,后面问是否要设置成上面的配置? 这里输入yes
集群创建成功了
 

5. 集群节点状态查看

 
集群主节点状态
redis-cli -p 7000 cluster nodes | grep master
集群从节点状态
redis-cli -p 7000 cluster nodes | grep slave
 
 
总共有三对:master和slave一一对应,符合预期.
 
也可以这样查看
[root@docker-01 ~]# redis-cli -p 7000 info replication
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.131,port=7003,state=online,offset=1540,lag=1
....
 
 

集群客户端

redis-cli -c -p 7000
set foo bar
get foo
 
#注意: 客户端进行操作的时候最好要加-c, 确保是集群模式,否则有时无法进行操作.因为就是因为-c参数可以保证在操作的客户端如果没有要找的node的话,会自动转发过去,从而获取到想要的结果,
 
重新分片
./redis-trib.rb reshard 127.0.0.1:7000
 
 

集群管理

集群主节点状态
redis-cli -p 7000 cluster nodes | grep master
集群从节点状态
redis-cli -p 7000 cluster nodes | grep slave
 
增加新的节点
./redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000
 
删除一个节点
redis-trib  del-node  ip:port  '<node-id>' 
删除master节点之前首先要使用reshard移除master的全部slot,然后再删除当前节点
 
添加一个从节点
./redis-trib.rb add-node  --slave  --master-id  $[nodeid] 127.0.0.1:7008 127.0.0.1:7000  
 
 

增加节点

一个新的节点需要至少一个从节点,这里我们在docker-01上添加
 

1. 准备工作

mkdir /data/7006
mkdir /data/7007
 
 
vim /data/7006/redis.conf
port 7006
daemonize yes
pidfile /data/7006/redis.pid
loglevel notice
logfile "/data/7006/redis.log"
dbfilename dump.rdb
dir /data/7006
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf # 添加好集群之后会保存集群的信息
cluster-node-timeout 5000
appendonly yes

  

vim /data/7007/redis.conf
port 7007
daemonize yes
pidfile /data/7007/redis.pid
loglevel notice
logfile "/data/7007/redis.log"
dbfilename dump.rdb
dir /data/7007
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

  

redis-server /data/7006/redis.conf
redis-server /data/7007/redis.conf
 

2.  添加主节点

 
redis-cli --cluster add-node 10.0.0.130:7006 10.0.0.130:7000
add-node命令将新节点的地址指定为第一个参数,并将集群中随机存在的节点(已经存在主从节点都可以)的地址指定为第二个参数
 
验证新节点是否已经加入集群
[root@docker-01 7006]# redis-cli -c -p 7000 cluster nodes | egrep 7006
623aaa030690211b641c08f6623f5b4468bf03b0 10.0.0.130:7006@17006 master - 0 1569460664357 0 connected
 
已经成功添加到新的集群当中了.
 
请注意,由于此节点已经连接到集群,因此它已经能够正确重定向客户端查询,并且通常来说是集群的一部分。但是,与其他master相比,它有两个特点:
  • 由于没有分配的哈希槽,因此不保存任何数据。
  • 因为它是没有分配插槽的主机,所以当从机要成为主机时,它不会参与选举过程。
所以我们需要为新添加的节点分配槽位(重新分片), 新节点才能被使用.
 
redis5 之前的版本添加方式
redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000
 

3. 转移slot(重新分片)

redis-cli --cluster reshard 10.0.0.130:7006 # 会进行交互式

>>> Performing Cluster Check (using node 10.0.0.130:7006)
M: 623aaa030690211b641c08f6623f5b4468bf03b0 10.0.0.130:7006
   slots: (0 slots) master
S: 8afb9a41f361e087cea56d3912b180db043fa6f7 10.0.0.132:7005
   slots: (0 slots) slave
   replicates b537e21aa9db60d2935f47bbd88a9ebd62168b16
S: c7f34873785eeddda818a4d1adce775cc3d01b1c 10.0.0.131:7003
   slots: (0 slots) slave
   replicates a59225315c983972554cd34e63336adad78001d6
M: b537e21aa9db60d2935f47bbd88a9ebd62168b16 10.0.0.131:7002
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: b5ed868eebf22825fd06888c7ebb426caab2a368 10.0.0.130:7001
   slots: (0 slots) slave
   replicates a9b353fe6e31b6cea4005215648f2c4ab6731f10
M: a9b353fe6e31b6cea4005215648f2c4ab6731f10 10.0.0.132:7004
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: a59225315c983972554cd34e63336adad78001d6 10.0.0.130:7000
   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)? 4096

问你要为新节点分配多少个槽位?有现在有一个有4个节点了16384/4=4096, 所以这里我们填4096

What is the receiving node ID? 623aaa030690211b641c08f6623f5b4468bf03b0
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

问要接受分片的node的id, 新加节点7006: 623aaa030690211b641c08f6623f5b4468bf03b0

问从哪个节点作为源分配槽位ID,这里选择: all, 即从已经存在所有的节点进行分配.
Do you want to proceed with the proposed reshard plan (yes/no)?

问是否从这些节点进行分配, 输入 yes

4. 验证主节点是否添加成功

可见新的redis 7006 已经从原有的三个节点平均分配了槽位累计刚好4096个

redis5 之前的版本重新分片

redis-trib.rb reshard 127.0.0.1:7000

5. 添加从节点

redis-cli --cluster add-node --cluster-slave --cluster-master-id 623aaa030690211b641c08f6623f5b4468bf03b0 10.0.0.130:7007 10.0.0.130:7006
参数说明:
--cluster-master-Id 指定要把从节点添加给哪个redis主节点的id
10.0.0.130:7007 要添加的从节点
10.0.0.130:7006 已经存在主节点7006

验证:

[root@docker-01 ~]# redis-cli -c -p 7000 cluster nodes |egrep '700[67]'
623aaa030690211b641c08f6623f5b4468bf03b0 10.0.0.130:7006@17006 master - 0 1569462389467 7 connected 0-1364 5461-6826 10923-12287
4ca37b1856b63ace09632a79b6788cccc47963ab 10.0.0.130:7007@17007 slave 623aaa030690211b641c08f6623f5b4468bf03b0 0 1569462387951 7 connected

  

已经成功把7007从节点,添加到集群中7006的主节点上了

注意:如果在生产环境,建议新添加的主从节点一定不要放在同一台服务器上面. 防止该服务器挂掉, 整个节点数据丢失的问题.
 
 
redis5之前版本添加从节点写法:
redis-trib.rb add-node --slave --master-id bff7d6e603578033f53865de3e55fb2b8c526b60 127.0.0.1:7007 127.0.0.1:7000

删除节点

redis-cli --cluster reshard 10.0.0.130:7006
 
redis5之前的版本写法:
redis-trib.rb reshard 127.0.0.1:7000
 
 
删除一个节点
 
主节点删除:
删除master节点之前首先要使用reshard移除master的全部slot,然后再删除当前节点
 
(1) 重新分片
 
这里我们要把源redis 7006节点上面的4096个槽位,分配到redis 7000上面
所以接受slot的node ID写上redis 7000的ID
下面会让你输入你要从把那个节点的slot重新分? 这里当然是redis 7006的ID
done代表已经输入完
 
下一行是让你确认是否要分片,输入yes
 
验证分片:
[root@docker-01 ~]# redis-cli -c -p 7000 cluster nodes
623aaa030690211b641c08f6623f5b4468bf03b0 10.0.0.130:7006@17006 master - 0 1569465429000 7 connected
c7f34873785eeddda818a4d1adce775cc3d01b1c 10.0.0.131:7003@17003 slave a59225315c983972554cd34e63336adad78001d6 0 1569465429000 8 connected
a9b353fe6e31b6cea4005215648f2c4ab6731f10 10.0.0.132:7004@17004 master - 0 1569465428000 3 connected 12288-16383
8afb9a41f361e087cea56d3912b180db043fa6f7 10.0.0.132:7005@17005 slave b537e21aa9db60d2935f47bbd88a9ebd62168b16 0 1569465429548 5 connected
a59225315c983972554cd34e63336adad78001d6 10.0.0.130:7000@17000 myself,master - 0 1569465429000 8 connected 0-6826 10923-12287
b537e21aa9db60d2935f47bbd88a9ebd62168b16 10.0.0.131:7002@17002 master - 0 1569465428000 2 connected 6827-10922
b5ed868eebf22825fd06888c7ebb426caab2a368 10.0.0.130:7001@17001 slave a9b353fe6e31b6cea4005215648f2c4ab6731f10 0 1569465429953 6 connected
4ca37b1856b63ace09632a79b6788cccc47963ab 10.0.0.130:7007@17007 slave a59225315c983972554cd34e63336adad78001d6 0 1569465428000 8 connected
[root@docker-01 ~]# 
[root@docker-01 ~]# 
[root@docker-01 ~]# 
[root@docker-01 ~]# redis-cli -c -p 7007 info replication
# Replication
role:slave
master_host:10.0.0.130
master_port:7000
master_link_status:up
....

我通过集群状态可以看出redis 7006已经没有slot了. 之前的集群从节点 redis 7007已经指定到 集群节点redis 7000上面了,因为我们把原来redis 7006所有的slot全部迁移到了redis 7000上面了.

(2). 开始删除主节点
redis-cli --cluster del-node 10.0.0.130:7006 623aaa030690211b641c08f6623f5b4468bf03b0
 
redis5 之前版本的写法
redis-trib.rb del-node 127.0.0.1:7006 bff7d6e603578033f53865de3e55fb2b8c526b6
 
验证: redis-cli -c -p 7000 cluster nodes
 
 

从节点删除:
redis-cli --cluster del-node 10.0.0.130:7007 4ca37b1856b63ace09632a79b6788cccc47963ab
 
redis5 之前版本的写法
redis-trib.rb del-node 127.0.0.1:7007 2af3da4252ad1a7334d476e1b56498b85a1b488c
 
验证: redis-cli -c -p 7000 cluster nodes

 

redis集群故障切换测试

接着上面

[root@docker-01 ~]# redis-cli -c -p 7000 cluster nodes
c7f34873785eeddda818a4d1adce775cc3d01b1c 10.0.0.131:7003@17003 slave a59225315c983972554cd34e63336adad78001d6 0 1569466576000 8 connected
a9b353fe6e31b6cea4005215648f2c4ab6731f10 10.0.0.132:7004@17004 master - 0 1569466577000 3 connected 12288-16383
8afb9a41f361e087cea56d3912b180db043fa6f7 10.0.0.132:7005@17005 slave b537e21aa9db60d2935f47bbd88a9ebd62168b16 0 1569466577000 5 connected
a59225315c983972554cd34e63336adad78001d6 10.0.0.130:7000@17000 myself,master - 0 1569466576000 8 connected 0-6826 10923-12287
b537e21aa9db60d2935f47bbd88a9ebd62168b16 10.0.0.131:7002@17002 master - 0 1569466577730 2 connected 6827-10922
b5ed868eebf22825fd06888c7ebb426caab2a368 10.0.0.130:7001@17001 slave a9b353fe6e31b6cea4005215648f2c4ab6731f10 0 1569466577529 6 connected

  

关闭主库测试

 
我把reids 7000 杀死
[root@docker-01 ~]# ps -ef|grep redis
root      74891      1  0 07:15 ?        00:01:32 redis-server *:7000 [cluster]
root      75699      1  0 07:16 ?        00:01:27 redis-server *:7001 [cluster]
root      82424  46420  0 10:56 pts/0    00:00:00 grep --color=auto redis
[root@docker-01 ~]# kill 74891
[root@docker-01 ~]# ps -ef|grep redis
root      75699      1  0 07:16 ?        00:01:27 redis-server *:7001 [cluster]
root      82842  46420  0 10:57 pts/0    00:00:00 grep --color=auto redis

  

我在docker03上(也可以在docker02)查看下日志
[root@docker-03 ~]# tail -f /data/700*/redis.log
==> /data/7004/redis.log <==
17074:M 26 Sep 2019 07:48:50.222 * Background saving started by pid 17098
17098:C 26 Sep 2019 07:48:50.264 * DB saved on disk
17098:C 26 Sep 2019 07:48:50.265 * RDB: 2 MB of memory used by copy-on-write
17074:M 26 Sep 2019 07:48:50.272 * Background saving terminated with success
17074:M 26 Sep 2019 07:48:50.272 # Cluster state changed: ok
17074:M 26 Sep 2019 07:48:50.272 * Synchronization with replica 10.0.0.130:7001 succeeded
17074:M 26 Sep 2019 10:57:23.966 * Marking node a59225315c983972554cd34e63336adad78001d6 as failing (quorum reached).
17074:M 26 Sep 2019 10:57:23.966 # Cluster state changed: fail
17074:M 26 Sep 2019 10:57:24.205 # Failover auth granted to c7f34873785eeddda818a4d1adce775cc3d01b1c for epoch 9
17074:M 26 Sep 2019 10:57:24.213 # Cluster state changed: ok

==> /data/7005/redis.log <==
17099:C 26 Sep 2019 07:48:50.437 * Parent agreed to stop sending diffs. Finalizing AOF...
17099:C 26 Sep 2019 07:48:50.437 * Concatenating 0.00 MB of AOF diff received from parent.
17099:C 26 Sep 2019 07:48:50.437 * SYNC append only file rewrite performed
17099:C 26 Sep 2019 07:48:50.437 * AOF rewrite: 4 MB of memory used by copy-on-write
17079:S 26 Sep 2019 07:48:50.524 * Background AOF rewrite terminated with success
17079:S 26 Sep 2019 07:48:50.524 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
17079:S 26 Sep 2019 07:48:50.524 * Background AOF rewrite finished successfully
17079:S 26 Sep 2019 10:57:23.966 * FAIL message received from b537e21aa9db60d2935f47bbd88a9ebd62168b16 about a59225315c983972554cd34e63336adad78001d6
17079:S 26 Sep 2019 10:57:23.966 # Cluster state changed: fail
17079:S 26 Sep 2019 10:57:24.213 # Cluster state changed: ok

  

通过日志可以看出, redis cluster已经把这个节点的主的权限交给了c7f34873785eeddda818a4d1adce775cc3d01b1c, 而这个ID是10.0.0.131 redis 7003, 刚好为 redis 7000的从库的ID
 
查看集群状态
[root@docker-02 ~]# redis-cli -c -p 7002 cluster nodes
b5ed868eebf22825fd06888c7ebb426caab2a368 10.0.0.130:7001@17001 slave a9b353fe6e31b6cea4005215648f2c4ab6731f10 0 1569467232651 6 connected
8afb9a41f361e087cea56d3912b180db043fa6f7 10.0.0.132:7005@17005 slave b537e21aa9db60d2935f47bbd88a9ebd62168b16 0 1569467232551 5 connected
a59225315c983972554cd34e63336adad78001d6 10.0.0.130:7000@17000 master,fail - 1569466638301 1569466637597 8 disconnected
b537e21aa9db60d2935f47bbd88a9ebd62168b16 10.0.0.131:7002@17002 myself,master - 0 1569467231000 2 connected 6827-10922
a9b353fe6e31b6cea4005215648f2c4ab6731f10 10.0.0.132:7004@17004 master - 0 1569467233663 3 connected 12288-16383
c7f34873785eeddda818a4d1adce775cc3d01b1c 10.0.0.131:7003@17003 master - 0 1569467232000 9 connected 0-6826 10923-12287

此时源docker01的redis 7000的从库 docker-02 redis 7003已经提升为了主库

 

重新启动主库测试

redis-server /data/7000/redis.conf
 
查看集群状态
[root@docker-02 ~]# redis-cli -c -p 7002 cluster nodes
b5ed868eebf22825fd06888c7ebb426caab2a368 10.0.0.130:7001@17001 slave a9b353fe6e31b6cea4005215648f2c4ab6731f10 0 1569467495195 6 connected
8afb9a41f361e087cea56d3912b180db043fa6f7 10.0.0.132:7005@17005 slave b537e21aa9db60d2935f47bbd88a9ebd62168b16 0 1569467496503 5 connected
a59225315c983972554cd34e63336adad78001d6 10.0.0.130:7000@17000 slave c7f34873785eeddda818a4d1adce775cc3d01b1c 0 1569467495000 9 connected
b537e21aa9db60d2935f47bbd88a9ebd62168b16 10.0.0.131:7002@17002 myself,master - 0 1569467494000 2 connected 6827-10922
a9b353fe6e31b6cea4005215648f2c4ab6731f10 10.0.0.132:7004@17004 master - 0 1569467496201 3 connected 12288-16383
c7f34873785eeddda818a4d1adce775cc3d01b1c 10.0.0.131:7003@17003 master - 0 1569467495000 9 connected 0-6826 10923-12287

  

通过集群状态可以看出重新启动的原redis主库, 已经变为从库.
 
也就是说当在redis cluster中,如果一个主库redis实例宕掉的话, 那么的它的从库将被提升为主库. 当主库再次上线时,它将成为原来从库(现在是主库)的从库.

原文地址:https://www.cnblogs.com/yang-ning/p/11642850.html