redis高可用有3种方式:主从,哨兵,集群
集群模式通过分片来解决写热点和数据容量问题,同时支持主从复制功能,解决读热点问题,并提供故障转移功能,实现高可用
本文将介绍集群中槽位的表示,在集群中执行命令的流程,重新分配槽位,以及复制与故障转移的流程
集群的数据被分为16384个槽(slot),数据库中的每个键都属于这16384个槽的其中一个,集群中的每个节点可以处理0个或最多16384个槽
每个节点会为集群中所有节点维护clusterNode 结构,用于记录其分配的槽位
struct clusterNode {
// ...
unsigned char slots[16384/8];
int numslots;
// ...
};
clusterNode.slots
能表示16384个比特位,如果数组中某下标对应的值为1,,表示该下标对应的槽位属于该节点
同时也会记录集群中,每个槽位被分配给了哪个节点:
typedef struct clusterState {
// ...
clusterNode *slots[16384];
// ...
} clusterState;
clusterState.slots
数组的每个元素代表一个节点,表示每个下标对应的槽位,被分配给了哪个节点
这里用两个结构保存的原因是:
i
是否已经被指派,或者槽i
被指派给了哪个节点,只需访问clusterState.slots[i]
即可,时间复杂度为O(1)
每次要将节点A的槽指派信息传播给其他节点时,访问clusterNode结构即可
也就是说,当一种结构无法满足多种业务场景时,redis通过冗余数据的方式,为每种业务场景都维护高效的数据结构
当集群中全部16384个槽位都被指定后,集群就会进入上线状态
某节点收到客户端的命令后,会检查要处理的键属于哪个槽:
MOVED
错误,包含槽位和目标地址,指引客户端转向至正确的节点,并再次发送之前想要执行的命令怎么计算某个键属于哪个槽位?
CRC16(key) & 16383
。先计算出key的CRC-16校验和,再&16383,计算出0到16383中间的一个数,就是槽位当集群中有节点下线,或进行扩缩容时,就需要重新分配槽位
由Redis的集群管理软件redis-trib执行:
假设要迁移的槽位是slot
在进行重新分片期间,可能会出现这样一种情况:属于被迁移槽的一部分键值对保存在源节点里
面,而另一部分键值对则保存在目标节点里面
当源节点收到客户端的命令,且要处理的恰好就在被迁移的槽位里:
ASK
错误,指引客户端转向正在导入槽的目标节点,再次发送之前想要执行的命令接到ASK错误的客户端会根据错误提供的IP地址和端口号,转向至正在导入槽的目标节点,然后首先向目标节点发送一个ASKING
命令,之后再重新发送原本想要执行的命令
ASKING命令唯一要做的就是打开发送该命令的客户端的REDIS_ASKING标识
为啥需要ASKING命令?
REDIS_ASKING
标识,就破例
执行一次命令ASK和MOVED错误都会导致客户端转向,它们的区别在于:
i
的MOVED错误之后,客户端每次遇到关于槽i
的命令请求时,都可以直接将命令请求发送至MOVED错误所指向的节点i
的命令请求产生任何影响Redis集群中的节点分为主节点(master)和从节点(slave),其中主节点用于处理槽,而从节点则用于复制某个主节点,并在被复制的主节点下线时,代替下线主节点继续处理命令请求
集群中的每个节点都会定期地向集群中的其他节点发送PING消息,以此来检测对方是否在线,如果接收PING消息的节点没有在规定的时间内向发送PING消息的节点返回PONG消息,那么发送PING消息的节点就会将接收PING消息的节点标记为疑似下线,并将该信息发给集群中其他节点
如果半数以上负责处理槽的主节点都将某个主节点x
报告为疑似下线,那么这个主节点x将被标记为已下线,将主节点x标记为已下线的节点会向集群广播一条关于主节点x的FAIL消息,这样所有收到这条FAIL消息的节点都会立即将主节点x标记为已下线
当一个从节点发现自己正在复制的主节点进入了已下线状态时,将开始对下线主节点进行故障转移:
CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST
消息,要求所有收到这条消息、并且具有投票权的主节点向这个从节点投票CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK
消息,表示这个主节点支持从节点成为新的主节点注意从节点并不是一发现主节点进入已下线状态就进行选举,而是会延迟一定时间
为啥要延迟?
延迟时间的计算公式为:500ms + random(0 ~ 500)ms + SLAVE_RANK * 1000ms
其中SLAVE_RANK
代表从节点已经从主节点复制数据的总量,RANK越小,代表数据越新,这样理论上有最新数据的从节点会先发起选举,符合一般业务要求
然后该节点执行如下操作,完成主从切换:
slave of no one
命令