Redis槽位分配与故障转移

一、Redis槽分配与键定位

两个数据结构

1、clusterNode

typedef clusterNode{
	...
	unsigned char slots[16384/8]; //redis共有16384个槽
	int numslots;  //表示节点处理的槽数量 
	...
} clusterNode;

该数组共2048个字节,16384个二进制位(每个位代表一个索引槽)。每个节点上都对应一个clusterNode,其二进制位为1,表示该槽位由该节点处理,为0则该节点不处理。

每个节点均会向其他节点发送自己处理的槽位信息,其他节点会将收到的信息更新到clusterState.nodes中与发送节点对应的记录中。

2、clusterState

typedef struct clusterState{
	...
	clusterNode *slots[16384];
	...
} clusterState;

其中slots[i]如果指向一个clusterNode表示该槽位已分配,否则(NULL)表示该槽位未分配。

用这两个数据结构主要是用于确定给定槽位是否已分配,其复杂度为O(1)。另外对于向其他节点广播自身处理的槽位信息时,无需遍历整个clusterState.slots数组来确定槽位与节点的对应关系,直接将自身clusterNode对应的slots数组发送即可。

确定键属于哪个槽

def slot_number(key) :
	return CRC16(key) & 16383;

计算出key值应该去往哪个槽之后,需要确定哪个节点处理该键,此时由上述clusterState.slot[index]给定的节点clusterNode确定。如果指向的clusterNode就是接收节点本身,那么直接处理请求。如果不是,向客户端返回MOVED信息,并携带IP及端口信息,告诉客户端转向。在收到MOVED信息之后,客户端转而向目标节点发起处理请求。

Redis的批量处理相关

当多个请求的key同属一个槽位时,可以使用批量操作,其效率较单个发起请求的操作要高得多。

redis的数据结构clusterState中有另外一个量用来表示槽位号slot与键的关系

typedef struct clusterState{
	...
	zskiplist *slots_to_keys;
	...
} clusterState;

利用此信息便可对属于某个或某些槽位的键进行批量操作。

重分片

在对集群进行水平扩容时需要进行重新分片,以使得槽位能分布到新加入的节点当中。
重分片可在线操作,而不影响现有业务的运行。
重分片操作可以通过Redis的集群管理软件redis-trib来执行。

重分片过程

重分片对应着Redis的部分槽位的转移,对应于该槽位的键转而由新的节点处理,从而每节点容纳的数据更多,以此达到扩容的目的。重分片的过程对应如下(由redis-trib执行相应命令):

1、告诉目标节点准备好从源节点导入属于slot的键值对
CLUSTER SETSLOT < slot> IMPORTING < source_id>

2、告诉源节点准备好将slot中的键值对迁移至目标节点
CLUSTER SETSLOT < slot> MIGRATING < target_id>

3、告诉源节点发送一定数目的键值对给目标节点
CLUSTER GETKEYSINSLOT < slot> < count>

4、对每个键,都向源节点发送MIGRATE < target_ip> < target_port> < key_name> 0 < timeout>将被选中的键原子地从源节点迁移至目标节点的slot中。

5、重复步骤3和4,直至slot中所有的key均迁移完成。

6、向集群中任意一个节点发送CLUSTER SETSLOT < slot> NODE < target_id>,该节点再将槽的分配信息更新到集群中所有其他节点。

二、故障检测与转移

Redis集群模式下,cluster-node-timeout参数(默认15秒)作为节点Fail的依据。

集群故障检测

集群中的每个节点都会定期地向其他节点发送PING报文,收到PING报文的节点会回复PONG报文。如果节点在规定时间内(上述timeout)没有收到某个节点的PONG报文,就将该节点标记为疑似下线状态PFAIL(probable fail)。其他节点通过集群状态信息交换,记录其他节点传来的节点疑似下线状态,当超过一半的节点将某个节点标记为疑似下线时,那么该节点就被标记为下线FAIL。然后进行FAIL标记的节点将该信息广播给其他节点,使其它节点都知道该节点已下线。

集群故障转移

在发现master节点下线后,会从所有从节点中通过选举产生新的主节点。
新的主节点更新之前指向下线主节点的槽指派关系,更新为指向自己。
向整个集群广播PONG消息,告知其他节点自己已成为新的主节点。
新的主节点全面接管已下线节点的槽位请求。

领导选举

从节点发现主节点下线之后,便要求其它主节点进行投票,以求备胎转正

1、具有投票权的节点:其它在线主节点,每个主节点只有一票可投
2、投给谁:收到的第一个发送CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST的从节点,回复CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK给从节点,表示认可其成为主节点
3、谁获胜:收到的CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK报文个数大于等于N/2+1(N表示参与投票的主节点数)

如果一次投票完成后没选出来怎么办?

自增计数器值加1,进行再次选举,其他主节点重新投票,重复该过程直到新的主节点被选举出来。

参考

《Redis设计与实现》

发布了95 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43878293/article/details/103596357