共计 1508 个字符,预计需要花费 4 分钟才能阅读完成。
每个节点都会保留集群的数据信息,具体对象是 clusterNode,这个对象里记录了每个节点创立工夫、节点名、节点标识、节点 IP、节点端口、负责的槽点等。
typedef struct clusterNode{
// 创立工夫
mstime_t ctime;
// 节点名
char name[REDIS_CLUSTER_NAMELEN];
// 节点标识,能够示意节点主从角色及节点高低线状态
int flags;
// 节点配置,用于故障转移
uint64_t configEpoch;
// 节点 ip 地址
char ip[REDIS_IP_STR_LEN];
// 节点端口
int port;
// 节点相干信息
clusterLink *link;
// 槽位
unsigned char slots[16384/8];
int numslots;
}clusterNode;
在集群中执行命令
客户端向节点发送命令时,节点会依据命令里的 key 先进行槽位的查看:
def CLUSTER_KEYSLOT(key):
// 计算槽位
slot = slot_number(key)
// 返回计算的槽位
reply_client(slot)
def slot_number(key):
return CRC16(key) & 16383
这里的 CRC16 用于计算 key 的 CRC_16 校验和(可参考 CRC 校验的原理及功能),& 16383 用于计算 0 到 16383 之间的整数(也就是槽位),计算出槽位后,节点会查看本人在 clusterState.slots 数组中的值,发现是本人负责的槽位后则执行客户端命令,如果发现不是本人负责解决的槽位则返回‘MOVED’谬误,指引客户端正确节点。
故障检测
集群中的每个节点都会定期向其它节点发送 PING 音讯,以此来检测对方是否在线,如果某节点没在规定工夫内响应 PONG 音讯,那么发送检测信息的节点会将对方标记为疑似下线 (PFAIL) 状态并记录在 clusterNode 的 flag 里。一旦半数以上的节点将某个节点都标记为了疑似下线状态,那其它节点会将这个节点由疑似下线标记为下线(FAIL)。
故障转移
当一个从节点发现正在复制的主节点是下线状态后,从节点会进行故障转移:
- 在之前主节点的所有从节点里选举出新的主节点。
- 新的主节点会撤销所有对收己下线主节点的槽指派,将这些槽全副指派给本人。
- 新的主节点向集群播送一条 PONG 音讯,让其它从节点晓得本人已成了主节点。
- 新的主节点开始接管和本人负责解决的槽无关的命令申请,实现故障转移。
选举主节点
- 当某个主节点呈现故障下线的时候,等提早一段时间后(上面进行阐明),它上面的从节点会向集群里播送一条要求其它主节点进行投票的音讯。
- 在同一轮投票中,每个主节点都有一次投票的机会,在它收到投票要求且本人还没进行投票时,它就会发动一次投票。
- 当一个从节点收集到大于等于 2N+ 1 的投票时,那这个从节点就成为了新的主节点;如果一轮投票里未能产生过半的投票则会进入下一轮的投票,直到主节点选举出。
为什么要进行一段时间的提早以及怎么做到提早呢?
节点之间相互进行通信是会一个先后,某个节点呈现了故障下线并不是所有节点都会在同一时间晓得,假如某个主节点下线了它上面的一个从节点马上发动投票,其它主节点可能并不知道这个主节点已下线而不进行投票。同时进行一个提早还能够免得所有从节点同时发动投票而导致平票。做到提早是通过上面公式来的:
DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
其中的 SLAVE_RANK 指的是此 slave 曾经从 master 复制数据的总量的 rank。rank 越小代表已复制的数据越新。一般来说,持有最新数据的 slave 将会首先发动选举。