本文介绍Redis Cluster模式下集群的可用性
搭建集群
利用Docker Compose搭建一个3主3从的Redis Cluster集群,docker-compose.yml文件如下
1 | # 构建一个3主3从的Redis集群 |
Redis指定版本的配置文件redis.conf可通过下述链接下载对应版本的安装包后解压后获取
1 | http://download.redis.io/releases/ |
修改Redis配置文件redis.conf
1 | ... |
这里对于集群中的6个节点,均使用上述同一个配置文件。目录结构如下所示
现在,进行docker-compose.yml文件所在目录,利用Docker Compose命令创建容器
1 | docker-compose up -d |
执行下述命令组建集群
1 | docker exec -it node-1 \ |
命令输出结果如下所示,其中在分配好每个节点的槽范围后,需要输入yes进行确认,以便完成集群构建
1 | Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. |
此时我们即可在任意一个节点容器中执行redis-cli命令来访问集群了
1 | # 以集群方式启动redis-cli(使用-c选项),可以自动进行重定向;反之,不行 |
现在向集群中添加key分别为age、name、country的数据。不难看出其分别存储到Master节点node1、node2、node3当中
如果期望从某Slave节点中访问其所存储的相应数据,需先发送readonly命令。如下所示
下文将会利用该集群对Redis Cluster的可用性进行探索。至此我们不难得出该集群的拓扑结构关系及部分key的分布,如下所示
Master下线
一个Master下线
Redis Cluster模式下,当某个Master被判定下线后,会进行故障转移Failover。基本流程如下:
- 从已经下线的Master节点所属的所有Slave节点中,挑选一个Slave节点作为新Master
- 让已经下线的Master节点所属的所有Slave节点,指向新Master。即从新Master进行复制
- 将已经下线的Master节点设置为新Master的从节点。这样当这个已经下线的Master节点后续重新上线时,其就会成为新Master的从节点。以避免某个槽中同时出现两个主节点的情形
对于上面的搭建3主3从的集群而言,如果我们停止Master节点node 2的容器使其下线。从下图不难看出,集群状态依然可用。node 2节点的状态为fail。node 6节点此前是node 2节点的Slave节点,现在则成为新Master,对外提供服务了
通过对key为name的数据进行访问、修改。进一步证明了node 6节点是Master节点了
此时,我们如果将node 2节点容器启动,会是什么情形呢?不难看出,node 2节点已经是新Master node 6节点的从节点了。因为当我们在node 6节点中修改key为name的数据后,可以从node 2节点中感知到变化
半数以上Master同时下线
对于上面的搭建3主3从的集群而言,如果我们将半数以上的Master同时下线,会怎么样呢?这里我们选择停止2个Master节点容器——node 2、node 3,会发生什么呢?
1 | # 停止 node 2、node 3 节点容器 |
现在我们通过node 1节点查看集群、节点状态,不仅node 2、node 3节点下线,而且整个集群都不可用。甚至对于node 1中key为age的数据都无法访问
我们知道node 2、node 3节点都有各自的slave节点——node 6、node 4。为什么在该场景下未进行故障转移Failover,使node 6、node 4成为新Master呢?原因其实很简单,在Redis Cluster模式下是不需要Sentinel哨兵的。故对于一个含有N个Master的集群而言,当一个Slave提升为新Master的要求,是需要至少获得集群中 N/2+1 个Master(即半数以上的Master)的投票数。换言之,当集群中可用Master节点不足半数以上,会导致集群不可用
对于这里含有3个Master的集群而言,半数以上Master投票数的要求是 N/2+1 = 3/2+1 = 2。当我们同时停止两个Master节点容器后,集群中只剩一个Master可以进行投票。使得node 6、node 4节点均无法满足最低投票数要求。进而导致整个集群不可用
原Master在故障转移后依次下线
从上文不难看出在Redis Cluster中,节点的角色不是固定的。因为当Master节点下线后,其下的Slave节点可以被提升为新Master节点。对于上面的搭建3主3从的集群而言,如果我们对原Master节点node 1、node 2、node 3依次进行下线,但保证每次下线某个原Master节点时,之前的下线节点已经完成了故障转移
具体地:
- 先下线原Master节点node 1,等待故障转移完成,使得node 5成为新Master
- 再下线原Master节点node 2,等待故障转移完成,使得node 6成为新Master
- 最后下线原Master节点node 3,等待故障转移完成,使得node 4成为新Master
如下所示,不难看到当某个原Master下线。由于集群中可用Master的数量(包括原Master、新Master)总是可以满足半数以上的要求,故其下的Slave总是可以会被提升为新Master。例如,当原Master节点node 2下线时,集群中可用的Master有两个:原Master节点node 3、新Master节点node 5
可以看到,原Master在故障转移后依次下线。此时集群中只有node 5、node 6、node 4这3个新Master节点了。自然集群依然是可用的
某个槽对应的主从节点全部下线
对于上面的搭建3主3从的集群而言,我们先将Master节点node 2下线,然后让node 6节点成为新Master
现在我们将node 6节点继续下线,这样该槽对应的所有节点(node 2、node 6)都已经全部下线了。此时,由于Redis集群中某个槽完全无法对外提供服务,会导致集群整体不可用。不仅无法访问存在于node 2、node 6中key为name的数据,而且对存在于node 1、node 3中key为age、country的数据也无法访问
事实上,这正是redis.conf配置文件中cluster-require-full-coverage配置项的作用。此前我们将该配置项设置为yes。即,当负责某个槽的主库下线且没有相应的从库进行故障恢复时,集群整体不可用。即使其他槽的节点未下线,也无法访问其中的数据
而这里,如果我们期望某个槽对应的所有节点(node 2、node 6)全部下线后。集群仍然可用,即可以访问其他槽(例如node1、node3)的数据。则可将cluster-require-full-coverage配置项修改为no,然后重启整个集群使之生效。这样当负责某个槽的主库下线且没有相应的从库进行故障恢复时,集群仍然可用。即可访问其他槽的数据
修改配置重启后,我们停止了node 2、node 6节点。此时集群状态依然可用。虽然无法访问存在于node 2、node 6中key为name的数据,但对存在于node 1、node 3中key为age、country的数据可以正常访问
总结
通过上文不难看出,Redis Cluster模式下集群不可用有两种情形:
- 当集群中可用Master节点不足半数以上,会导致集群不可用
- 当cluster-require-full-coverage配置项为yes时,某个槽对应的主从节点全部下线,会导致集群不可用;当cluster-require-full-coverage配置项为no时,某个槽对应的主从节点全部下线,集群中其他槽的数据可以正常访问