Redis集群是Redis提供的分布式数据库方案,集群通过分片(sharding)来进行数据共享,并提供复制和故障转移功能。
实际上,切片集群是一种保存大量数据的通用机制,这个机制可以有不同的实现方案。在 Redis 3.0 之前,官方并没有针对切片集群提供具体的方案。从 3.0 开始,官方提供了一个名为 Redis Cluster 的方案,用于实现切片集群。Redis Cluster 方案中就规定了数据和实例的对应规则。本文以Redis 3.0 之后官方提供Redis Cluster为基础。


一个Redis集群通常由多个实例组成,在刚开始的时候,每个节点都是相互独立的,它们都处于一个只包含自己的集群当中,要组建一个真正可工作的集群,我们必须将各个独立的节点连接起来,构成一个包含多个实例的集群。
CLUSTER MEET
例如: 实例1将实例2加入到集群
CLUSTER MEET 127.0.0.1 7002
以实例1将实例2加入到集群为例说明,收到命令的实例A将与实例B进行握手(handshake),以此来确认彼此的存在,并为将来的进一步通信打好基础:
握手过程如下图

说明:clusterNode结构保存了一个实例的当前状态,比如实例的创建时间、实例的名字、实例的IP地址和端口号等等。每个实例都会使用一个clusterNode结构来记录自己的状态,并为集群中的所有其他实例(包括主实例和从实例)都创建一个相应的clusterNode结构,以此来记录其他实例的状态
Redis集群通过分片的方式来保存数据库中的键值对:集群的整个数据库被分为16384个槽(slot),数据库中的每个键都属于这16384个槽的其中一个,集群中的每个节点可以处理0个或最多16384个槽。
当数据库中的16384个槽都有节点在处理时,集群处于上线状态(ok);相反地,如果数据库中有任何一个槽没有得到处理,那么集群处于下线状态(fail)。
通过向节点发送CLUSTER ADDSLOTS命令,可以将一个或多个槽指派(assign)给节点负责, 命令如下:
CLUSTER ADDSLOTS [slot ...]
例如:将槽0至槽5000指派给实例1负责, 在实例1上执行以下命令:
CLUSTER ADDSLOTS 0 1 2 3 4 ... 5000
同理:将槽5001至槽10000指派给实例2负责, 在实例2上执行以下命令:
CLUSTER ADDSLOTS 5001 5002 ... 10000
同理:将槽10001至槽16383指派给实例3负责, 在实例3上执行以下命令:
CLUSTER ADDSLOTS 10001 10002 ... 16383
当以上三个CLUSTER ADDSLOTS命令都执行完毕之后,数据库中的16384个槽都已经被指派给了相应的节点,集群进入上线状态。
一般来说,客户端和集群实例建立连接后,实例就会把哈希槽的分配信息发给客户端。但是,在集群刚刚创建的时候,每个实例只知道自己被分配了哪些哈希槽,是不知道其他实例拥有的哈希槽信息的。那么,客户端为什么可以在访问任何一个实例时,都能获得所有的哈希槽信息呢?
答案:这是因为Redis实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散(Gossip协议)。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。
客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。

重定向是指客户端给一个实例发送数据读写操作时,这个实例上并没有相应的数据,实例就会向客
户端返回一个MOVED错误,指引客户端转向至正在负责槽的实例。
MOVED的格式为:
MOVED :
其中slot为键所在的槽,而ip和port则是负责处理槽slot的节点的IP地址和端口号。
示例:
MOVED 10086 127.0.0.1:7003
表示槽10086正由IP地址为127.0.0.1,端口号为7003的节点负责。
Redis集群的重新分片操作可以将任意数量已经指派给某个节点(源节点)的槽改为指派给另一个节点(目标节点),并且相关槽所属的键值对也会从源节点被移动到目标节点。
重新分片操作可以在线(online)进行,在重新分片的过程中,集群不需要下线,并且源节点和目标节点都可以继续处理命令请求。
例如:对于之前的包含7001、7002、7003三个实例的集群来说,向这个集群添加一个IP为127.0.0.1,端口号为7004的实例,然后通过重新分片操作,将原本指派给节点7003的槽15001至16383改为指派给节点7004。
Redis集群的重新分片操作是由Redis的集群管理软件redis-trib负责执行的,Redis提供了进行重新分片所需的所有命令,而redis-trib则通过向源节点和目标节点发送命令来进行重新分片操作。
redis-trib对集群的单个槽slot进行重新分片的步骤如下:
步骤5,每次迁移过程图:

重新分片流程图:

在进行重新分片期间,源节点向目标节点迁移一个槽的过程中,可能会出现这样一种情况:属于被迁移槽的一部分键值对保存在源节点里面,而另一部分键值对则保存在目标节点里面。
当客户端向源节点发送一个与数据库键有关的命令,并且命令要处理的数据库键恰好就属于正在被迁移的槽时:
说明:ASKING 命令让这个实例允许执行客户端接下来发送的命令
判断是否发送ASK错误的过程图

| MOVED | ASK | |
|---|---|---|
| 是否更新客户端缓存的哈希槽分配信息 | 是 | 否 |
| 槽的负责权是否已经从一个节点转移到了另一个节点 | 是 | 否 |
消息
集群中的各个节点通过发送和接收消息(message)来进行通信,我们称发送消息的节点为发送者(sender),接收消息的节点为接收者。
节点发送的消息主要有以下五种: