文章目录
1. Redis Cluster 的架构
从 redis 3.0 版本之后,redis 支持 Redis-Cluster集群作为分布式解决方案。该集群采用多主多从结构,使用多个 Master节点保存数据和整个集群状态,通过增减 Master节点就能达到增大/缩小 Redis 数据容量的目的,从而很好地支持横向扩容
Redis Cluster 集群的结构特点如下:
- 集群内支持多个 Master 节点,每个 Master 节点也可以有多个 Slave 节点。所有节点彼此连接(基于PING-PONG机制),内部使用二进制协议通信
- 集群中超过半数的 Master 节点检测到某个节点失效时才判定该节点下线
- 客户端与集群中任意一个可用 Master 节点直连
- 集群内置数据自动分片机制,将集群内部所有的 key 映射到
16384个Slot中,每个 Master 节点都会记录哪些 Slot 指派给了自己,哪些指派给了其他节点。这种机制让集群内节点的增加和移除很简单,增加一个 Master 节点就将其他节点的 Slot 移动部分过去,减少一个Master 就将它的 Slot 移动到其他节点即可,移动 Slot 的成本是非常低的- 客户端连接集群中任意 Master 节点即可发送命令,不过在命令执行之前会根据 key 使用
CRC16(key)%16384定位到一个 Slot,如果该 Slot 不在当前 Master 节点的负责范围内,则当前节点会将负责该 Slot 的节点地址返回给客户端,客户端收到后自动将原请求重新发往目标节点
RedisCluster 设计成 16384 个 Slot 的原因
可参考 作者的回答,主要有以下几个方面的考虑
- 心跳包的大小
因为 redis 节点需要定时发送一定数量的 ping 消息作为心跳包,而在包的消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。如果 Slot 数量太大,如 65536,则这块的大小是: 65536÷8=8kb,ping 消息的消息头太大了,浪费带宽- 集群节点数量有限
集群节点越多心跳包的消息体内携带的数据越多,如果节点数量超过一定限制,也会导致网络拥堵,从而使集群内节点达到最终一致性的时间相对变长,因此不建议集群内节点数量超过1000个,在这样的情况下,16384个 Slot 足够使用- 传输效率
Redis 主节点的配置信息中,其负责的 Slot 通过一个 bitmap 位图来保存。在网络传输过程中,bitmap 会被压缩,但是如果 bitmap 的填充率slots/N(N表示节点数)很高的话,bitmap 的压缩率就很低。在节点数量有限的情况下,Slot 数量尽量小可以提高 bitmap 的压缩率,从而减少网络流量
2. 集群内部通信机制
2.1 RedisCluster 节点间通信方式
RedisCluster 集群内每个 Master 节点会使用两个端口,一个是提供服务的端口,比如 6379,另外一个是该端口号加10000的端口号,比如16379,这个端口号是专门用来进行节点间通信的,也就是集群总线
RedisCluster 不是将集群元数据(节点信息,故障信息,节点的增加和移除,slot信息等)集中存储在单个节点上,而是在所有节点间采取Gossip协议不断进行通信的方式保持集群中每个节点上的元数据的同步更新。具体来说,就是每个节点每隔一段时间都会往另外几个节点发送 PING 消息,其他节点接收到 PING 之后返回 PONG 消息,互相交换元数据
- gossip 优点
元数据的更新比较分散,不是集中在一个节点,更新请求会陆续打到所有节点上去更新,有一定的延时,降低了压力- gossip 缺点
元数据更新有延时,可能导致集群的一些变化在各个节点上存在一段时间的同步滞后
2.2 Gossip 协议
Gossip协议又被称为流言协议,是 Redis 集群各个节点彼此同步状态的手段。其工作方式很简单,以加入新节点(Meet) 为例,最初只有发出邀请的节点和被邀请节点知道这件事,但是通过 Ping 消息一层一层扩散,其他节点也被通知到了,这样Gossip协议实现了最终一致性
Gossip 算法又被称为反熵(Anti-Entropy),就是在混乱中寻求一致,这也说明了Gossip 的特点:在一个有界网络中,每个节点可能知道所有其他节点,也可能仅知道几个邻居节点,只要这些节点可以通过网络连通,并且每个节点都随机地与其他节点通信,那么经过一番杂乱无章的交流,最终所有节点的状态都会达成一致
RedisCluster 的集群消息主要有以下几种类型:
- Meet
通过cluster meet ip port命令,已有集群的某个节点会向新加入的节点发送邀请,使其加入现有集群- Ping
每个节点都会频繁地给其他节点发送 Ping,每次会选择5个最久没有通信的其他节点,如果发现某个节点通信延时达到了cluster_node_timeout/2,那么立即发送 Ping,避免数据长时间不一致。cluster_node_timeout可以用来调节 Ping 的频率,如果该值设置得比较大,那么会减少 Ping 次数。Ping 消息中包含了节点自己的状态及其维护的集群元数据,还会带上至少两个已知的其他节点信息一起发送出去,进行数据交换- Pong
节点收到 Ping 消息后会回复 Pong 消息,消息中同样带有自己节点的信息及已知的其他节点信息- Fail
某节点判定一个节点 Fail 后,会立即向集群所有节点广播该节点挂掉的消息,其他节点收到消息后标记指定的节点已下线
3. 高可用性原理
RedisCluster 高可用的原理和哨兵机制及其相似,其主要原理如下:
- Master 节点宕机判定
如果一个 Master 节点 ping 了另外一个节点,这个节点在cluster-node-timeout超时时间内一直没有返回 pong,那么就被认为 PFAIL ,主观宕机
如果一个节点认为某个节点 PFAIL 了,那么会在 ping 消息中将这个信息广播给其他节点,如果多个节点(N/2 + 1)都认为目标节点 pfail了,那么这个节点就会变成 fail,客观宕机- Slave 节点切换为 Master 节点
对宕机的 Master 节点,需要从其所有的从节点中选择一个切换成 Master 节点。这个过程中大概分为了 3 个步骤:
- 过滤可用的 Slave 节点
具体做法就是检查每个 Slave 节点与 Master 节点断开连接的时间,如果超过了cluster-node-timeout * cluster-slave-validity-factor,那这个Slave 节点就没有资格切换成 Master- 确定候选节点优先级
过滤出可用的 Slave 节点后,哨兵会对所有从节点进行排序,排序因子为 slave priority,offset 和 run id,每个从节点根据优先级设置一个选举时间,选举时间靠前的 Slave 节点优先进行选举- 选举出 Master 节点
所有的 Master 节点开始对 Slave 节点进行选举投票,如果大部分Master节点(N/2 + 1)都投票给了某个 Slave 节点,那么选举通过,这个 Slave 节点将执行主备切换,切换为新的 Master 节点