Redis 缓存因其访问性能高、可靠性更高,作为缓存工具在各大互联网公司中广泛使用。今天我们就来看看Redis Cluster 的实现原理。
集群建立
Redis集群是由多个Redis节点组成,每个Redis节点都是相互独立的,为了组建一个redis集群,我们需要使用CLUSTER MEET命令把他们连接起来。 节点A通过接收客户端发来的LUSTER MEET命令将另一个节点B加入到集群中,接收到命令的节点A将与节点B进行握手来来确认彼此的存在。下图显示了它们握手的过程。
握手完成后,节点A会将节点B的信息通过Gossip协议传播给集群中的其他节点,让其他节点与节点B完成握手,之后节点B就会被集群中的所有节点认识了。
槽指派
集群建立之后,那么接下来要解决的就是数据分布问题了。Redis缓存信息是使用 Key-Value 的形式来存储数据,Redis集群又将整个数据分布16384个槽中。在存储信息的时候,集群会对每个要存储的Key计算CRC16 校验值并对 16384 取模(slot = CRC16(key)%16384)。由于集群中的槽会被指派到不同的节点,从而实现了数据的分布式存储。
每个节点都保存着一个clusterNode结构,该结构里有一个slots属性记录了节点负责处理哪些槽。
struct clusterNode{
//......
unsigned char slots[16384/8];
//......
}
这个slots属性是个二进制位的数组,数组长度为16384/8=2048个字节,共包含16384个二进制位。每个二进制位代表一个槽,节点会根据二进制位上的值进行判断该节点是否负责处理这个槽,1代表处理,0代表不处理。
表格中代表的是该节点负责集群中的槽1、3、5、7,这种处理方式可以很快的得出节点是否负责处理某个槽的数据。
指令执行
在集群中的16384个槽都进行了指派之后,集群就进入了上线状态,这时客户端就可以向集群发送数据命令了。 当客户端向节点发送GET/SET指令时,收到指令的节点会先对指令操作的key进行计算,得出该key值应该存储在哪个槽中,并检查这个槽是否指派给了自己。
故障转移与恢复
Redis集群中的节点分为主节点(master)和从节点(slave),主节点主要负责处理槽,从节点则用于复制某个主节点数据,并在被复制的主节点下线时,代替主节点处理后续的命令请求。
针对节点下线有两种状态:
1.主观下线:当节点A想节点B发送了一条PING消息时,节点B没有在规定的时间内(设置的cluster-node-timeout参数)返回PONG消息,那么节点A会将节点B标记为主观下线状态。
这里的主观下线只是节点A主观的认为节点B下线了,有可能是因为节点A和节点B之间的网络断了,但是其他节点依然可以和节点B通讯,所以主观下线并不一定是节点B真的就下线了。
2.客观下线:由于节点A与集群内的其他节点仍然保持通讯,因此节点B的下线消息也通过Gossip协议传遍了集群内的其他节点。
当集群内半数以上的节点都认为节点B主观下线了,那么节点B就会被认为客观下线了,同时将节点B标记为客观下线的节点会向集群中发送一条FAIL消息,所有收到这条消息的节点会立即将节点B标记为客观下线。
如果一个节点被认为客观下线了,那么就需要从它的从节点当中选出一个节点来代替它成为主节点。选举过程如下:
a.当从节点发现自己正在复制的主节点被标记为客观下线时,从节点会向集群中发送一条CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST消息,要求所有收到这条消息的具有投票权的主节点向这个从节点投票
b.如果一个主节点具有投票权,并且未投票给其他从节点,那么这个主节点会向要求投票的从节点返回一条CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,表示这个主节点支持该从节点成为新的主节点
c.每个从节点都会接收返回的CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,并会进行统计自己得到了多少主节点的支持
d.每个具有投票权的主节点只能投一次票,当一个从节点获得了一半以上的主节点的支持票时,那么这个节点就会成为新的主节点,
e.如果没有任何一个从节点获取大于半数的投票,那么将进行新的选举,直到选出新的主节点为止。
f.新的主节点产生后,它会撤销所有对已下线的主节点的槽指派,并将这些槽指派给自己。
g.新的主节点会向集群中广播一条PONG消息,让集群中的其他节点直到这个从节点已经成为了新的主节点,并且接管了原先主节点的所有槽。
h.新的主节点负责接收和自己处理的槽相关的指令,至此故障转移结束。
结束语
本文通过对集群建立、槽指派、指令执行、故障转移与恢复的实现原理进行分析,一步一步的带大家认识Redis集群。希望对大家认识和了解Redis集群有所帮助。
(版权归原作者所有,侵删)